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/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()