Support IPv4 multicast in P4 fabric pipeline

- Multicast can use the same table as unicast. Merge into one.
- Allow masked destination MAC in classifier table

Note:
- Pipeliner now translates all exact MAC match to masked match with FF:FF:FF:FF:FF:FF mask.
- Interpreter now only uses masked src/dst MAC

Change-Id: Ibd27ebfb2d72ba929031f07a29927eb6f1844f11
(cherry picked from commit 0865779b66a59a623856b1353615e462af5575c5)
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 7601ca7..ca38cf8 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
@@ -133,7 +133,7 @@
         TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
 
         PiAction mappedAction = interpreter.mapTreatment(treatment,
-                                                         FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4);
+                                                         FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4);
         PiAction expectedAction = PiAction.builder()
                 .withId(FabricConstants.NOP)
                 .build();
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 5769e8f..9ceb869 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
@@ -76,24 +76,27 @@
         actualFlowRule = flowRulesInstalled.get(1);
         flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
                                                           ROUTER_MAC,
+                                                          null,
                                                           Ethernet.TYPE_IPV4,
-                                                          FWD_IPV4_UNICAST);
+                                                          FabricFilteringPipeliner.FWD_IPV4_ROUTING);
         assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
 
         // forwarding classifier ipv6
         actualFlowRule = flowRulesInstalled.get(2);
         flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
                                                           ROUTER_MAC,
+                                                          null,
                                                           Ethernet.TYPE_IPV6,
-                                                          FWD_IPV6_UNICAST);
+                                                          FabricFilteringPipeliner.FWD_IPV6_ROUTING);
         assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
 
         // forwarding classifier mpls
         actualFlowRule = flowRulesInstalled.get(3);
         flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
                                                           ROUTER_MAC,
+                                                          null,
                                                           Ethernet.MPLS_UNICAST,
-                                                          FWD_MPLS);
+                                                          FabricFilteringPipeliner.FWD_MPLS);
         assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
     }
 
@@ -112,7 +115,7 @@
                 .permit()
                 .withPriority(PRIORITY)
                 .withKey(Criteria.matchInPort(PORT_1))
-                .addCondition(Criteria.matchEthDst(MacAddress.IPV4_MULTICAST))
+                .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST, MacAddress.IPV4_MULTICAST_MASK))
                 .addCondition(Criteria.matchVlanId(VlanId.NONE))
                 .withMeta(treatment)
                 .fromApp(APP_ID)
@@ -137,8 +140,9 @@
         actualFlowRule = flowRulesInstalled.get(1);
         flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
                                                           MacAddress.IPV4_MULTICAST,
+                                                          MacAddress.IPV4_MULTICAST_MASK,
                                                           Ethernet.TYPE_IPV4,
-                                                          FWD_IPV4_MULTICAST);
+                                                          FabricFilteringPipeliner.FWD_IPV4_ROUTING);
         assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
     }
 
@@ -157,7 +161,7 @@
                 .permit()
                 .withPriority(PRIORITY)
                 .withKey(Criteria.matchInPort(PORT_1))
-                .addCondition(Criteria.matchEthDst(MacAddress.IPV6_MULTICAST))
+                .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV6_MULTICAST, MacAddress.IPV6_MULTICAST_MASK))
                 .addCondition(Criteria.matchVlanId(VlanId.NONE))
                 .withMeta(treatment)
                 .fromApp(APP_ID)
@@ -182,8 +186,9 @@
         actualFlowRule = flowRulesInstalled.get(1);
         flowRuleExpected = buildExpectedFwdClassifierRule(PORT_1,
                                                           MacAddress.IPV6_MULTICAST,
+                                                          MacAddress.IPV6_MULTICAST_MASK,
                                                           Ethernet.TYPE_IPV6,
-                                                          FWD_IPV6_MULTICAST);
+                                                          FabricFilteringPipeliner.FWD_IPV6_ROUTING);
         assertTrue(flowRuleExpected.exactMatch(actualFlowRule));
     }
 
@@ -329,13 +334,19 @@
 
     private FlowRule buildExpectedFwdClassifierRule(PortNumber inPort,
                                                     MacAddress dstMac,
+                                                    MacAddress dstMacMask,
                                                     short ethType,
                                                     byte fwdClass) {
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthDst(dstMac)
+        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
                 .matchInPort(inPort)
-                .matchEthType(ethType)
-                .build();
+                .matchEthType(ethType);
+        if (dstMacMask != null) {
+            sbuilder.matchEthDstMasked(dstMac, dstMacMask);
+        } else {
+            sbuilder.matchEthDstMasked(dstMac, MacAddress.EXACT_MASK);
+        }
+        TrafficSelector selector = sbuilder.build();
+
         PiActionParam classParam = new PiActionParam(FabricConstants.FWD_TYPE,
                                                      ImmutableByteSequence.copyFrom(fwdClass));
         PiAction fwdClassifierAction = PiAction.builder()
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java
index 77bb035..bb06dd3 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java
@@ -20,6 +20,7 @@
 import org.junit.Test;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
+import org.onlab.packet.MacAddress;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.UDP;
 import org.onosproject.net.flow.DefaultFlowRule;
@@ -28,6 +29,8 @@
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
 import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.net.group.GroupDescription;
@@ -145,7 +148,7 @@
                 .matchEthDst(HOST_MAC)
                 .build();
         testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING,
-                            selector, selector, NEXT_ID_1);
+                            buildExpectedSelector(selector), selector, NEXT_ID_1);
     }
 
     @Test
@@ -166,7 +169,7 @@
         TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
                 .matchIPDst(IPV4_UNICAST_ADDR)
                 .build();
-        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4,
+        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
                             expectedSelector, selector, NEXT_ID_1);
     }
 
@@ -179,7 +182,7 @@
         TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
                 .matchIPDst(IPV4_UNICAST_ADDR)
                 .build();
-        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4,
+        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
                             expectedSelector, selector, null);
     }
 
@@ -194,7 +197,7 @@
         TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
                 .matchIPDst(IPV4_MCAST_ADDR)
                 .build();
-        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4,
+        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
                             expectedSelector, selector, NEXT_ID_1);
     }
 
@@ -208,7 +211,7 @@
         TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
                 .matchIPDst(IPV6_UNICAST_ADDR)
                 .build();
-        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V6,
+        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6,
                             expectedSelector, selector, NEXT_ID_1);
 
     }
@@ -224,7 +227,7 @@
         TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
                 .matchIPDst(IPV6_MCAST_ADDR)
                 .build();
-        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V6,
+        testSpecificForward(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6,
                             expectedSelector, selector, NEXT_ID_1);
     }
 
@@ -264,10 +267,10 @@
 
             if (expectedTableId.equals(FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING)) {
                 setNextIdAction.withId(FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_BRIDGING);
-            } else if (expectedTableId.equals(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4)) {
-                setNextIdAction.withId(FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_UNICAST_V4);
-            } else if (expectedTableId.equals(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V6)) {
-                setNextIdAction.withId(FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_UNICAST_V6);
+            } else if (expectedTableId.equals(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4)) {
+                setNextIdAction.withId(FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V4);
+            } else if (expectedTableId.equals(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6)) {
+                setNextIdAction.withId(FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V6);
             }
 
             setNextIdTreatment = DefaultTrafficTreatment.builder()
@@ -314,4 +317,16 @@
 
         assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
     }
+
+    private TrafficSelector buildExpectedSelector(TrafficSelector selector) {
+        TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+        selector.criteria().forEach(c -> {
+            if (c.type() == Criterion.Type.ETH_DST) {
+                sbuilder.matchEthDstMasked(((EthCriterion) c).mac(), MacAddress.EXACT_MASK);
+            } else {
+                sbuilder.add(c);
+            }
+        });
+        return sbuilder.build();
+    }
 }
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 5e08aa2..c361377 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
@@ -61,14 +61,6 @@
             .matchVlanId(VLAN_100)
             .build();
 
-    // Forwarding types
-    static final byte FWD_BRIDGING = 0;
-    static final byte FWD_MPLS = 1;
-    static final byte FWD_IPV4_UNICAST = 2;
-    static final byte FWD_IPV4_MULTICAST = 3;
-    static final byte FWD_IPV6_UNICAST = 4;
-    static final byte FWD_IPV6_MULTICAST = 5;
-
     static final PiCriterion VLAN_VALID = PiCriterion.builder()
             .matchExact(FabricConstants.HDR_VLAN_TAG_IS_VALID, new byte[]{1})
             .build();
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java
index 5e77906..1ef11c2 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java
@@ -72,7 +72,7 @@
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPDst(IPV4_UNICAST_ADDR)
                 .build();
-        testFft(selector, ForwardingFunctionType.IPV4_UNICAST);
+        testFft(selector, ForwardingFunctionType.IPV4_ROUTING);
     }
 
     @Test
@@ -82,7 +82,7 @@
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPDst(IPV4_MCAST_ADDR)
                 .build();
-        testFft(selector, ForwardingFunctionType.IPV4_MULTICAST);
+        testFft(selector, ForwardingFunctionType.IPV4_ROUTING);
     }
 
     @Test
@@ -92,7 +92,7 @@
                 .matchEthType(Ethernet.TYPE_IPV6)
                 .matchIPDst(IPV6_UNICAST_ADDR)
                 .build();
-        testFft(selector, ForwardingFunctionType.IPV6_UNICAST);
+        testFft(selector, ForwardingFunctionType.IPV6_ROUTING);
     }
 
     @Test
@@ -102,7 +102,7 @@
                 .matchEthType(Ethernet.TYPE_IPV6)
                 .matchIPDst(IPV6_MCAST_ADDR)
                 .build();
-        testFft(selector, ForwardingFunctionType.IPV4_MULTICAST);
+        testFft(selector, ForwardingFunctionType.IPV4_ROUTING);
     }
 
     @Test