Support in fabric pipeliner for pushing double VLAN tag in Next obj

- Small modification to better support pop and route
- To support route and push we expect to receive a Next Objective with two VLAN_ID
- Added capability to check if the pipeline support double VLAN termination

Change-Id: I8bfbf61ccd838a069121e5ab4a804f695a446bac
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
index e59086b..bf37694 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
@@ -29,6 +29,9 @@
 import org.onosproject.net.pi.runtime.PiAction;
 import org.onosproject.net.pi.runtime.PiActionParam;
 
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -43,9 +46,15 @@
 
     private FabricInterpreter interpreter;
 
+    FabricCapabilities allCapabilities;
+
     @Before
     public void setup() {
-        interpreter = new FabricInterpreter();
+        allCapabilities = createNiceMock(FabricCapabilities.class);
+        expect(allCapabilities.hasHashedTable()).andReturn(true).anyTimes();
+        expect(allCapabilities.supportDoubleVlanTerm()).andReturn(true).anyTimes();
+        replay(allCapabilities);
+        interpreter = new FabricInterpreter(allCapabilities);
     }
 
     /* Filtering control block */
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipelinerTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipelinerTest.java
index dbb2bd4..e15b117 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipelinerTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipelinerTest.java
@@ -265,6 +265,52 @@
     }
 
     /**
+     * Test double VLAN pop filtering objective
+     * Creates one rule for ingress_port_vlan table and 3 rules for
+     * fwd_classifier table (IPv4, IPv6 and MPLS unicast) when
+     * the condition is MAC + VLAN + INNER_VLAN.
+     */
+    @Test
+    public void testPopVlan() throws FabricPipelinerException {
+        FilteringObjective filteringObjective = DefaultFilteringObjective.builder()
+                .withKey(Criteria.matchInPort(PORT_1))
+                .addCondition(Criteria.matchEthDst(ROUTER_MAC))
+                .addCondition(Criteria.matchVlanId(VLAN_100))
+                .addCondition(Criteria.matchInnerVlanId(VLAN_200))
+                .withPriority(PRIORITY)
+                .fromApp(APP_ID)
+                .withMeta(DefaultTrafficTreatment.builder()
+                                  .popVlan()
+                                  .build())
+                .permit()
+                .add();
+        ObjectiveTranslation actualTranslation = translator.translate(filteringObjective);
+
+        // Ingress port vlan rule
+        FlowRule inportFlowRuleExpected = buildExpectedVlanInPortRule(
+                PORT_1, VLAN_100, VLAN_200, VlanId.NONE,
+                FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN);
+        // Forwarding classifier rules (ipv6, ipv4, mpls)
+        FlowRule classifierV4FlowRuleExpected = buildExpectedFwdClassifierRule(
+                PORT_1, ROUTER_MAC, null,  Ethernet.TYPE_IPV4,
+                FilteringObjectiveTranslator.FWD_IPV4_ROUTING);
+        FlowRule classifierV6FlowRuleExpected = buildExpectedFwdClassifierRule(
+                PORT_1, ROUTER_MAC, null,  Ethernet.TYPE_IPV6,
+                FilteringObjectiveTranslator.FWD_IPV6_ROUTING);
+        FlowRule classifierMplsFlowRuleExpected = buildExpectedFwdClassifierRule(
+                PORT_1, ROUTER_MAC, null,  Ethernet.MPLS_UNICAST,
+                FilteringObjectiveTranslator.FWD_MPLS);
+        ObjectiveTranslation expectedTranslation = ObjectiveTranslation.builder()
+                .addFlowRule(inportFlowRuleExpected)
+                .addFlowRule(classifierV4FlowRuleExpected)
+                .addFlowRule(classifierV6FlowRuleExpected)
+                .addFlowRule(classifierMplsFlowRuleExpected)
+                .build();
+
+        assertEquals(expectedTranslation, actualTranslation);
+    }
+
+    /**
      * Incorrect filtering key or filtering conditions test.
      */
     @Test
@@ -381,6 +427,9 @@
                     .build();
         } else {
             selector.matchVlanId(vlanId);
+            if (vlanValid(innerVlanId)) {
+                selector.matchInnerVlanId(innerVlanId);
+            }
             piAction = PiAction.builder()
                     .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
                     .build();
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
index cf7d741..28f699c 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
@@ -207,6 +207,88 @@
     }
 
     /**
+     * Test Route and Push Next Objective (set mac, set double vlan and output port).
+     */
+    @Test
+    public void testRouteAndPushNextObjective() throws FabricPipelinerException {
+        TrafficTreatment routeAndPushTreatment = DefaultTrafficTreatment.builder()
+                .setEthSrc(ROUTER_MAC)
+                .setEthDst(HOST_MAC)
+                .setOutput(PORT_1)
+                .setVlanId(VLAN_100)
+                .pushVlan()
+                .setVlanId(VLAN_200)
+                .build();
+
+        NextObjective nextObjective = DefaultNextObjective.builder()
+                .withId(NEXT_ID_1)
+                .withPriority(PRIORITY)
+                .addTreatment(routeAndPushTreatment)
+                .withType(NextObjective.Type.SIMPLE)
+                .makePermanent()
+                .fromApp(APP_ID)
+                .add();
+
+        ObjectiveTranslation actualTranslation = translatorSimple.translate(nextObjective);
+
+        PiAction piActionRouting = PiAction.builder()
+                .withId(FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE)
+                .withParameter(new PiActionParam(
+                        FabricConstants.SMAC, ROUTER_MAC.toBytes()))
+                .withParameter(new PiActionParam(
+                        FabricConstants.DMAC, HOST_MAC.toBytes()))
+                .withParameter(new PiActionParam(
+                        FabricConstants.PORT_NUM, PORT_1.toLong()))
+                .build();
+
+        PiAction piActionPush = PiAction.builder()
+                .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_DOUBLE_VLAN)
+                .withParameter(new PiActionParam(
+                        FabricConstants.INNER_VLAN_ID, VLAN_100.toShort()))
+                .withParameter(new PiActionParam(
+                        FabricConstants.OUTER_VLAN_ID, VLAN_200.toShort()))
+                .build();
+
+
+        TrafficSelector nextIdSelector = DefaultTrafficSelector.builder()
+                .matchPi(PiCriterion.builder()
+                                 .matchExact(FabricConstants.HDR_NEXT_ID, NEXT_ID_1)
+                                 .build())
+                .build();
+        FlowRule expectedFlowRuleRouting = DefaultFlowRule.builder()
+                .forDevice(DEVICE_ID)
+                .fromApp(APP_ID)
+                .makePermanent()
+                // FIXME: currently next objective doesn't support priority, ignore this
+                .withPriority(0)
+                .forTable(FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE)
+                .withSelector(nextIdSelector)
+                .withTreatment(DefaultTrafficTreatment.builder()
+                                       .piTableAction(piActionRouting).build())
+                .build();
+        FlowRule expectedFlowRuleDoublePush = DefaultFlowRule.builder()
+                .withSelector(nextIdSelector)
+                .withTreatment(DefaultTrafficTreatment.builder()
+                                       .piTableAction(piActionPush)
+                                       .build())
+                .forTable(FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN)
+                .makePermanent()
+                // FIXME: currently next objective doesn't support priority, ignore this
+                .withPriority(0)
+                .forDevice(DEVICE_ID)
+                .fromApp(APP_ID)
+                .build();
+
+        ObjectiveTranslation expectedTranslation = ObjectiveTranslation.builder()
+                .addFlowRule(expectedFlowRuleDoublePush)
+                .addFlowRule(expectedFlowRuleRouting)
+                .build();
+
+
+        assertEquals(expectedTranslation, actualTranslation);
+    }
+
+    /**
      * Test program ecmp output group for Hashed table.
      */
     @Test
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
index 619a0b7..6c3551b 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
@@ -41,6 +41,7 @@
     static final PortNumber PORT_1 = PortNumber.portNumber(1);
     static final PortNumber PORT_2 = PortNumber.portNumber(2);
     static final VlanId VLAN_100 = VlanId.vlanId("100");
+    static final VlanId VLAN_200 = VlanId.vlanId("200");
     static final MacAddress HOST_MAC = MacAddress.valueOf("00:00:00:00:00:01");
     static final MacAddress ROUTER_MAC = MacAddress.valueOf("00:00:00:00:02:01");
     static final IpPrefix IPV4_UNICAST_ADDR = IpPrefix.valueOf("10.0.0.1/32");
@@ -61,6 +62,7 @@
         this.capabilitiesSimple = createNiceMock(FabricCapabilities.class);
         expect(capabilitiesHashed.hasHashedTable()).andReturn(true).anyTimes();
         expect(capabilitiesSimple.hasHashedTable()).andReturn(false).anyTimes();
+        expect(capabilitiesSimple.supportDoubleVlanTerm()).andReturn(true).anyTimes();
         replay(capabilitiesHashed);
         replay(capabilitiesSimple);
     }