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/main/java/org/onosproject/pipelines/fabric/FabricConstants.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
index 5b29faa..0c0b380 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
@@ -78,52 +78,48 @@
     public static final PiMatchFieldId HDR_ETHERNET_DST_ADDR =
             PiMatchFieldId.of("hdr.ethernet.dst_addr");
     // Table IDs
+    public static final PiTableId FABRIC_INGRESS_FORWARDING_ACL =
+            PiTableId.of("FabricIngress.forwarding.acl");
     public static final PiTableId FABRIC_INGRESS_NEXT_HASHED =
             PiTableId.of("FabricIngress.next.hashed");
-    public static final PiTableId FABRIC_INGRESS_FORWARDING_MULTICAST_V4 =
-            PiTableId.of("FabricIngress.forwarding.multicast_v4");
-    public static final PiTableId FABRIC_INGRESS_FORWARDING_MULTICAST_V6 =
-            PiTableId.of("FabricIngress.forwarding.multicast_v6");
-    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_SOURCE_TB_INT_SOURCE =
-            PiTableId.of("FabricEgress.process_int_source.tb_int_source");
-    public static final PiTableId FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER =
-            PiTableId.of("FabricIngress.filtering.fwd_classifier");
-    public static final PiTableId FABRIC_INGRESS_FORWARDING_UNICAST_V4 =
-            PiTableId.of("FabricIngress.forwarding.unicast_v4");
-    public static final PiTableId FABRIC_INGRESS_FORWARDING_UNICAST_V6 =
-            PiTableId.of("FabricIngress.forwarding.unicast_v6");
-    public static final PiTableId FABRIC_INGRESS_NEXT_SIMPLE =
-            PiTableId.of("FabricIngress.next.simple");
-    public static final PiTableId FABRIC_INGRESS_NEXT_MULTICAST =
-            PiTableId.of("FabricIngress.next.multicast");
     public static final PiTableId FABRIC_INGRESS_FORWARDING_MPLS =
             PiTableId.of("FabricIngress.forwarding.mpls");
+    public static final PiTableId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SINK =
+            PiTableId.of("FabricIngress.process_set_source_sink.tb_set_sink");
+    public static final PiTableId FABRIC_INGRESS_FORWARDING_ROUTING_V4 =
+            PiTableId.of("FabricIngress.forwarding.routing_v4");
+    public static final PiTableId FABRIC_INGRESS_NEXT_SIMPLE =
+            PiTableId.of("FabricIngress.next.simple");
+    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_SOURCE_TB_INT_SOURCE =
+            PiTableId.of("FabricEgress.process_int_source.tb_int_source");
     public static final PiTableId FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INST_0003 =
             PiTableId.of("FabricEgress.process_int_transit.tb_int_inst_0003");
+    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INSERT =
+            PiTableId.of("FabricEgress.process_int_transit.tb_int_insert");
+    public static final PiTableId FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER =
+            PiTableId.of("FabricIngress.filtering.fwd_classifier");
+    public static final PiTableId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SOURCE =
+            PiTableId.of("FabricIngress.process_set_source_sink.tb_set_source");
+    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_REPORT_TB_GENERATE_REPORT =
+            PiTableId.of("FabricEgress.process_int_report.tb_generate_report");
+    public static final PiTableId FABRIC_INGRESS_FORWARDING_BRIDGING =
+            PiTableId.of("FabricIngress.forwarding.bridging");
     public static final PiTableId FABRIC_INGRESS_SPGW_INGRESS_S1U_FILTER_TABLE =
             PiTableId.of("FabricIngress.spgw_ingress.s1u_filter_table");
     public static final PiTableId FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN =
             PiTableId.of("FabricIngress.filtering.ingress_port_vlan");
-    public static final PiTableId FABRIC_INGRESS_FORWARDING_ACL =
-            PiTableId.of("FabricIngress.forwarding.acl");
-    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_REPORT_TB_GENERATE_REPORT =
-            PiTableId.of("FabricEgress.process_int_report.tb_generate_report");
-    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INST_0407 =
-            PiTableId.of("FabricEgress.process_int_transit.tb_int_inst_0407");
-    public static final PiTableId FABRIC_INGRESS_FORWARDING_BRIDGING =
-            PiTableId.of("FabricIngress.forwarding.bridging");
     public static final PiTableId FABRIC_INGRESS_SPGW_INGRESS_DL_SESS_LOOKUP =
             PiTableId.of("FabricIngress.spgw_ingress.dl_sess_lookup");
-    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INSERT =
-            PiTableId.of("FabricEgress.process_int_transit.tb_int_insert");
-    public static final PiTableId FABRIC_INGRESS_NEXT_VLAN_META =
-            PiTableId.of("FabricIngress.next.vlan_meta");
+    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INST_0407 =
+            PiTableId.of("FabricEgress.process_int_transit.tb_int_inst_0407");
     public static final PiTableId FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN =
             PiTableId.of("FabricEgress.egress_next.egress_vlan");
-    public static final PiTableId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SINK =
-            PiTableId.of("FabricIngress.process_set_source_sink.tb_set_sink");
-    public static final PiTableId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SOURCE =
-            PiTableId.of("FabricIngress.process_set_source_sink.tb_set_source");
+    public static final PiTableId FABRIC_INGRESS_NEXT_MULTICAST =
+            PiTableId.of("FabricIngress.next.multicast");
+    public static final PiTableId FABRIC_INGRESS_NEXT_VLAN_META =
+            PiTableId.of("FabricIngress.next.vlan_meta");
+    public static final PiTableId FABRIC_INGRESS_FORWARDING_ROUTING_V6 =
+            PiTableId.of("FabricIngress.forwarding.routing_v6");
     // Indirect Counter IDs
     public static final PiCounterId FABRIC_INGRESS_PORT_COUNTERS_CONTROL_EGRESS_PORT_COUNTER =
             PiCounterId.of("FabricIngress.port_counters_control.egress_port_counter");
@@ -134,40 +130,36 @@
             PiCounterId.of("FabricIngress.forwarding.acl_counter");
     public static final PiCounterId FABRIC_INGRESS_NEXT_MULTICAST_COUNTER =
             PiCounterId.of("FabricIngress.next.multicast_counter");
-    public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_TRANSIT_COUNTER_INT_INST_0407 =
-            PiCounterId.of("FabricEgress.process_int_transit.counter_int_inst_0407");
-    public static final PiCounterId FABRIC_INGRESS_FORWARDING_UNICAST_V6_COUNTER =
-            PiCounterId.of("FabricIngress.forwarding.unicast_v6_counter");
+    public static final PiCounterId FABRIC_INGRESS_NEXT_VLAN_META_COUNTER =
+            PiCounterId.of("FabricIngress.next.vlan_meta_counter");
     public static final PiCounterId FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER_COUNTER =
             PiCounterId.of("FabricIngress.filtering.fwd_classifier_counter");
     public static final PiCounterId FABRIC_INGRESS_FORWARDING_BRIDGING_COUNTER =
             PiCounterId.of("FabricIngress.forwarding.bridging_counter");
-    public static final PiCounterId FABRIC_INGRESS_FORWARDING_MULTICAST_V6_COUNTER =
-            PiCounterId.of("FabricIngress.forwarding.multicast_v6_counter");
+    public static final PiCounterId FABRIC_INGRESS_FORWARDING_ROUTING_V4_COUNTER =
+            PiCounterId.of("FabricIngress.forwarding.routing_v4_counter");
     public static final PiCounterId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_COUNTER_SET_SOURCE =
             PiCounterId.of("FabricIngress.process_set_source_sink.counter_set_source");
-    public static final PiCounterId FABRIC_INGRESS_FORWARDING_MULTICAST_V4_COUNTER =
-            PiCounterId.of("FabricIngress.forwarding.multicast_v4_counter");
+    public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_TRANSIT_COUNTER_INT_INST_0407 =
+            PiCounterId.of("FabricEgress.process_int_transit.counter_int_inst_0407");
     public static final PiCounterId FABRIC_INGRESS_SPGW_INGRESS_UE_COUNTER =
             PiCounterId.of("FabricIngress.spgw_ingress.ue_counter");
     public static final PiCounterId FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN_COUNTER =
             PiCounterId.of("FabricEgress.egress_next.egress_vlan_counter");
-    public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_TRANSIT_COUNTER_INT_INSERT =
-            PiCounterId.of("FabricEgress.process_int_transit.counter_int_insert");
-    public static final PiCounterId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_COUNTER_SET_SINK =
-            PiCounterId.of("FabricIngress.process_set_source_sink.counter_set_sink");
-    public static final PiCounterId FABRIC_INGRESS_NEXT_VLAN_META_COUNTER =
-            PiCounterId.of("FabricIngress.next.vlan_meta_counter");
-    public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_SOURCE_COUNTER_INT_SOURCE =
-            PiCounterId.of("FabricEgress.process_int_source.counter_int_source");
-    public static final PiCounterId FABRIC_INGRESS_FORWARDING_UNICAST_V4_COUNTER =
-            PiCounterId.of("FabricIngress.forwarding.unicast_v4_counter");
     public static final PiCounterId FABRIC_INGRESS_NEXT_SIMPLE_COUNTER =
             PiCounterId.of("FabricIngress.next.simple_counter");
-    public static final PiCounterId FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN_COUNTER =
-            PiCounterId.of("FabricIngress.filtering.ingress_port_vlan_counter");
+    public static final PiCounterId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_COUNTER_SET_SINK =
+            PiCounterId.of("FabricIngress.process_set_source_sink.counter_set_sink");
+    public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_TRANSIT_COUNTER_INT_INSERT =
+            PiCounterId.of("FabricEgress.process_int_transit.counter_int_insert");
+    public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_SOURCE_COUNTER_INT_SOURCE =
+            PiCounterId.of("FabricEgress.process_int_source.counter_int_source");
     public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_TRANSIT_COUNTER_INT_INST_0003 =
             PiCounterId.of("FabricEgress.process_int_transit.counter_int_inst_0003");
+    public static final PiCounterId FABRIC_INGRESS_FORWARDING_ROUTING_V6_COUNTER =
+            PiCounterId.of("FabricIngress.forwarding.routing_v6_counter");
+    public static final PiCounterId FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN_COUNTER =
+            PiCounterId.of("FabricIngress.filtering.ingress_port_vlan_counter");
     public static final PiCounterId FABRIC_INGRESS_FORWARDING_MPLS_COUNTER =
             PiCounterId.of("FabricIngress.forwarding.mpls_counter");
     public static final PiCounterId FABRIC_INGRESS_NEXT_HASHED_COUNTER =
@@ -237,8 +229,12 @@
             PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i3");
     public static final PiActionId FABRIC_INGRESS_NEXT_SET_MCAST_GROUP =
             PiActionId.of("FabricIngress.next.set_mcast_group");
+    public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V4 =
+            PiActionId.of("FabricIngress.forwarding.set_next_id_routing_v4");
     public static final PiActionId FABRIC_EGRESS_PROCESS_INT_OUTER_ENCAP_INT_UPDATE_UDP =
             PiActionId.of("FabricEgress.process_int_outer_encap.int_update_udp");
+    public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V6 =
+            PiActionId.of("FabricIngress.forwarding.set_next_id_routing_v6");
     public static final PiActionId FABRIC_INGRESS_SPGW_INGRESS_SET_DL_SESS_INFO =
             PiActionId.of("FabricIngress.spgw_ingress.set_dl_sess_info");
     public static final PiActionId FABRIC_INGRESS_FILTERING_PUSH_INTERNAL_VLAN =
@@ -272,12 +268,8 @@
             PiActionId.of("FabricEgress.process_int_outer_encap.int_update_shim");
     public static final PiActionId FABRIC_INGRESS_NEXT_MPLS_ROUTING_V4_HASHED =
             PiActionId.of("FabricIngress.next.mpls_routing_v4_hashed");
-    public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_UNICAST_V6 =
-            PiActionId.of("FabricIngress.forwarding.set_next_id_unicast_v6");
     public static final PiActionId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_INT_SET_SOURCE =
             PiActionId.of("FabricIngress.process_set_source_sink.int_set_source");
-    public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_UNICAST_V4 =
-            PiActionId.of("FabricIngress.forwarding.set_next_id_unicast_v4");
     public static final PiActionId NOP = PiActionId.of("nop");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_DROP =
             PiActionId.of("FabricIngress.forwarding.drop");
@@ -308,12 +300,8 @@
     public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I2 =
             PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i2");
     public static final PiActionId NO_ACTION = PiActionId.of("NoAction");
-    public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_MULTICAST_V6 =
-            PiActionId.of("FabricIngress.forwarding.set_next_id_multicast_v6");
     public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_TRANSIT =
             PiActionId.of("FabricEgress.process_int_transit.int_transit");
-    public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_MULTICAST_V4 =
-            PiActionId.of("FabricIngress.forwarding.set_next_id_multicast_v4");
     public static final PiActionId FABRIC_INGRESS_NEXT_MPLS_ROUTING_V4_SIMPLE =
             PiActionId.of("FabricIngress.next.mpls_routing_v4_simple");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_NOP_ACL =
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
index 6031afd..b3f996d 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
@@ -70,18 +70,16 @@
                     .put(1, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER)
                     // Forwarding
                     .put(2, FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS)
-                    .put(3, FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4)
-                    .put(4, FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V6)
-                    .put(5, FabricConstants.FABRIC_INGRESS_FORWARDING_MULTICAST_V4)
-                    .put(6, FabricConstants.FABRIC_INGRESS_FORWARDING_MULTICAST_V6)
-                    .put(7, FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING)
-                    .put(8, FabricConstants.FABRIC_INGRESS_FORWARDING_ACL)
+                    .put(3, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4)
+                    .put(4, FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6)
+                    .put(5, FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING)
+                    .put(6, FabricConstants.FABRIC_INGRESS_FORWARDING_ACL)
                     // Next
-                    .put(9, FabricConstants.FABRIC_INGRESS_NEXT_VLAN_META)
-                    .put(10, FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE)
-                    .put(11, FabricConstants.FABRIC_INGRESS_NEXT_HASHED)
-                    .put(12, FabricConstants.FABRIC_INGRESS_NEXT_MULTICAST)
-                    .put(13, FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN)
+                    .put(7, FabricConstants.FABRIC_INGRESS_NEXT_VLAN_META)
+                    .put(8, FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE)
+                    .put(9, FabricConstants.FABRIC_INGRESS_NEXT_HASHED)
+                    .put(10, FabricConstants.FABRIC_INGRESS_NEXT_MULTICAST)
+                    .put(11, FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN)
                     .build();
 
     private static final Set<PiTableId> FILTERING_CTRL_TBLS =
@@ -89,10 +87,8 @@
                             FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER);
     private static final Set<PiTableId> FORWARDING_CTRL_TBLS =
             ImmutableSet.of(FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS,
-                            FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4,
-                            FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V6,
-                            FabricConstants.FABRIC_INGRESS_FORWARDING_MULTICAST_V4,
-                            FabricConstants.FABRIC_INGRESS_FORWARDING_MULTICAST_V6,
+                            FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
+                            FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6,
                             FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING,
                             FabricConstants.FABRIC_INGRESS_FORWARDING_ACL);
     private static final Set<PiTableId> NEXT_CTRL_TBLS =
@@ -106,8 +102,8 @@
     private static final ImmutableMap<Criterion.Type, PiMatchFieldId> CRITERION_MAP =
             ImmutableMap.<Criterion.Type, PiMatchFieldId>builder()
                     .put(Criterion.Type.IN_PORT, FabricConstants.STANDARD_METADATA_INGRESS_PORT)
-                    .put(Criterion.Type.ETH_DST, FabricConstants.HDR_ETHERNET_DST_ADDR)
-                    .put(Criterion.Type.ETH_SRC, FabricConstants.HDR_ETHERNET_SRC_ADDR)
+                    .put(Criterion.Type.ETH_DST_MASKED, FabricConstants.HDR_ETHERNET_DST_ADDR)
+                    .put(Criterion.Type.ETH_SRC_MASKED, FabricConstants.HDR_ETHERNET_SRC_ADDR)
                     .put(Criterion.Type.ETH_TYPE, FabricConstants.HDR_VLAN_TAG_ETHER_TYPE)
                     .put(Criterion.Type.MPLS_LABEL, FabricConstants.HDR_MPLS_LABEL)
                     .put(Criterion.Type.VLAN_VID, FabricConstants.HDR_VLAN_TAG_VLAN_ID)
@@ -122,8 +118,8 @@
     private static final ImmutableMap<PiMatchFieldId, Criterion.Type> INVERSE_CRITERION_MAP =
             ImmutableMap.<PiMatchFieldId, Criterion.Type>builder()
                     .put(FabricConstants.STANDARD_METADATA_INGRESS_PORT, Criterion.Type.IN_PORT)
-                    .put(FabricConstants.HDR_ETHERNET_DST_ADDR, Criterion.Type.ETH_DST)
-                    .put(FabricConstants.HDR_ETHERNET_SRC_ADDR, Criterion.Type.ETH_SRC)
+                    .put(FabricConstants.HDR_ETHERNET_DST_ADDR, Criterion.Type.ETH_DST_MASKED)
+                    .put(FabricConstants.HDR_ETHERNET_SRC_ADDR, Criterion.Type.ETH_SRC_MASKED)
                     .put(FabricConstants.HDR_VLAN_TAG_ETHER_TYPE, Criterion.Type.ETH_TYPE)
                     .put(FabricConstants.HDR_MPLS_LABEL, Criterion.Type.MPLS_LABEL)
                     .put(FabricConstants.HDR_VLAN_TAG_VLAN_ID, Criterion.Type.VLAN_VID)
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipeliner.java
index a8515e5..7d6ad40 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricFilteringPipeliner.java
@@ -51,12 +51,10 @@
 public class FabricFilteringPipeliner {
     private static final Logger log = getLogger(FabricFilteringPipeliner.class);
     // Forwarding types
-    private static final byte FWD_BRIDGING = 0;
-    private static final byte FWD_MPLS = 1;
-    private static final byte FWD_IPV4_UNICAST = 2;
-    private static final byte FWD_IPV4_MULTICAST = 3;
-    private static final byte FWD_IPV6_UNICAST = 4;
-    private static final byte FWD_IPV6_MULTICAST = 5;
+    static final byte FWD_BRIDGING = 0;
+    static final byte FWD_MPLS = 1;
+    static final byte FWD_IPV4_ROUTING = 2;
+    static final byte FWD_IPV6_ROUTING = 3;
     private static final PiCriterion VLAN_VALID = PiCriterion.builder()
             .matchExact(FabricConstants.HDR_VLAN_TAG_IS_VALID, new byte[]{1})
             .build();
@@ -104,11 +102,16 @@
                 .map(criterion -> (EthCriterion) criterion)
                 .findFirst()
                 .orElse(null);
+        EthCriterion ethDstMaskedCriterion = filterObjective.conditions().stream()
+                .filter(criterion -> criterion.type() == Criterion.Type.ETH_DST_MASKED)
+                .map(criterion -> (EthCriterion) criterion)
+                .findFirst()
+                .orElse(null);
 
         FlowRule inPortVlanTableRule = createInPortVlanTable(inPortCriterion, vlanCriterion,
                                                              filterObjective);
         Collection<FlowRule> fwdClassifierRules = createFwdClassifierRules(inPortCriterion, ethDstCriterion,
-                                                                           filterObjective);
+                                                                           ethDstMaskedCriterion, filterObjective);
 
         resultBuilder.addFlowRule(inPortVlanTableRule);
         fwdClassifierRules.forEach(resultBuilder::addFlowRule);
@@ -155,38 +158,46 @@
 
     private Collection<FlowRule> createFwdClassifierRules(PortCriterion inPortCriterion,
                                                           EthCriterion ethDstCriterion,
+                                                          EthCriterion ethDstMaskedCriterion,
                                                           FilteringObjective filterObjective) {
+        PortNumber port = inPortCriterion.port();
+
         Collection<FlowRule> flowRules = Lists.newArrayList();
         if (ethDstCriterion == null) {
-            // Bridging table, do nothing
+            if (ethDstMaskedCriterion == null) {
+                // Bridging table, do nothing
+                return flowRules;
+            }
+            // Masked fwd classifier rule
+            MacAddress dstMac = ethDstMaskedCriterion.mac();
+            MacAddress dstMacMask = ethDstMaskedCriterion.mask();
+            FlowRule flow = createMaskedFwdClassifierRule(port, dstMac, dstMacMask, filterObjective);
+            if (flow != null) {
+                flowRules.add(flow);
+            }
             return flowRules;
         }
-        PortNumber port = inPortCriterion.port();
         MacAddress dstMac = ethDstCriterion.mac();
-        if (dstMac.isMulticast()) {
-            flowRules.add(createMulticastFwdClassifierRule(port, dstMac, filterObjective));
-            return flowRules;
-        }
-
         flowRules.addAll(createIpFwdClassifierRules(port, dstMac, filterObjective));
         flowRules.add(createMplsFwdClassifierRule(port, dstMac, filterObjective));
         return flowRules;
     }
 
-    private FlowRule createMulticastFwdClassifierRule(PortNumber inPort, MacAddress dstMac,
-                                                      FilteringObjective filterObjective) {
+    private FlowRule createMaskedFwdClassifierRule(PortNumber inPort, MacAddress dstMac, MacAddress dstMacMask,
+                                                   FilteringObjective filterObjective) {
         TrafficTreatment treatment;
         short ethType;
-        if (dstMac.equals(MacAddress.IPV4_MULTICAST)) {
-            // Ipv4 multicast
-            treatment = createFwdClassifierTreatment(FWD_IPV4_MULTICAST);
+        if (dstMac.equals(MacAddress.IPV4_MULTICAST) && dstMacMask.equals(MacAddress.IPV4_MULTICAST_MASK)) {
+            treatment = createFwdClassifierTreatment(FWD_IPV4_ROUTING);
             ethType = Ethernet.TYPE_IPV4;
-        } else {
-            // IPv6 multicast
-            treatment = createFwdClassifierTreatment(FWD_IPV6_MULTICAST);
+        } else if (dstMac.equals(MacAddress.IPV6_MULTICAST) && dstMacMask.equals(MacAddress.IPV6_MULTICAST_MASK)) {
+            treatment = createFwdClassifierTreatment(FWD_IPV6_ROUTING);
             ethType = Ethernet.TYPE_IPV6;
+        } else {
+            log.warn("Unsupported masked fwd classifier rule. mac={}. mask={}", dstMac, dstMacMask);
+            return null;
         }
-        return createFwdClassifierRule(inPort, ethType, dstMac, treatment, filterObjective);
+        return createFwdClassifierRule(inPort, ethType, dstMac, dstMacMask, treatment, filterObjective);
     }
 
     private Collection<FlowRule> createIpFwdClassifierRules(PortNumber inPort,
@@ -194,10 +205,10 @@
                                                             FilteringObjective filterObjective) {
         Collection<FlowRule> flowRules = Lists.newArrayList();
         TrafficTreatment treatment;
-        treatment = createFwdClassifierTreatment(FWD_IPV4_UNICAST);
-        flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV4, dstMac, treatment, filterObjective));
-        treatment = createFwdClassifierTreatment(FWD_IPV6_UNICAST);
-        flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV6, dstMac, treatment, filterObjective));
+        treatment = createFwdClassifierTreatment(FWD_IPV4_ROUTING);
+        flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV4, dstMac, null, treatment, filterObjective));
+        treatment = createFwdClassifierTreatment(FWD_IPV6_ROUTING);
+        flowRules.add(createFwdClassifierRule(inPort, Ethernet.TYPE_IPV6, dstMac, null, treatment, filterObjective));
         return flowRules;
     }
 
@@ -205,18 +216,23 @@
                                                  MacAddress dstMac,
                                                  FilteringObjective filterObjective) {
         TrafficTreatment treatment = createFwdClassifierTreatment(FWD_MPLS);
-        return createFwdClassifierRule(inPort, Ethernet.MPLS_UNICAST, dstMac, treatment, filterObjective);
+        return createFwdClassifierRule(inPort, Ethernet.MPLS_UNICAST, dstMac, null, treatment, filterObjective);
     }
 
     private FlowRule createFwdClassifierRule(PortNumber inPort,
                                              short ethType,
                                              MacAddress dstMac,
+                                             MacAddress dstMacMask,
                                              TrafficTreatment treatment,
                                              FilteringObjective filterObjective) {
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
                 .matchInPort(inPort)
-                .matchEthDst(dstMac)
                 .matchEthType(ethType);
+        if (dstMacMask != null) {
+            selector.matchEthDstMasked(dstMac, dstMacMask);
+        } else {
+            selector.matchEthDstMasked(dstMac, MacAddress.EXACT_MASK);
+        }
 
         return DefaultFlowRule.builder()
                 .withSelector(selector.build())
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java
index bdc6d5e..580d398 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java
@@ -145,15 +145,13 @@
             case L2_BROADCAST:
                 processL2BroadcastRule(vlanIdCriterion, fwd, resultBuilder);
                 break;
-            case IPV4_UNICAST:
-                processIpv4UnicastRule(ipDstCriterion, fwd, resultBuilder);
+            case IPV4_ROUTING:
+                processIpv4RoutingRule(ipDstCriterion, fwd, resultBuilder);
                 break;
             case MPLS:
                 processMplsRule(mplsCriterion, fwd, resultBuilder);
                 break;
-            case IPV4_MULTICAST:
-            case IPV6_UNICAST:
-            case IPV6_MULTICAST:
+            case IPV6_ROUTING:
             default:
                 log.warn("Unsupported forwarding function type {}", criteria);
                 resultBuilder.setError(ObjectiveError.UNSUPPORTED);
@@ -174,7 +172,7 @@
 
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchVlanId(vlanId)
-                .matchEthDst(ethDst)
+                .matchEthDstMasked(ethDst, MacAddress.EXACT_MASK)
                 .build();
         TrafficTreatment treatment = fwd.treatment();
         if (fwd.nextId() != null) {
@@ -223,7 +221,7 @@
         resultBuilder.addFlowRule(flowRule);
     }
 
-    private void processIpv4UnicastRule(IPCriterion ipDstCriterion, ForwardingObjective fwd,
+    private void processIpv4RoutingRule(IPCriterion ipDstCriterion, ForwardingObjective fwd,
                                         PipelinerTranslationResult.Builder resultBuilder) {
         checkNotNull(ipDstCriterion, "IP dst criterion should not be null");
         TrafficSelector selector = DefaultTrafficSelector.builder()
@@ -232,7 +230,7 @@
         TrafficTreatment treatment = fwd.treatment();
         if (fwd.nextId() != null) {
             treatment = buildSetNextIdTreatment(fwd.nextId(),
-                                                FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_UNICAST_V4);
+                                                FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V4);
         }
         FlowRule flowRule = DefaultFlowRule.builder()
                 .withSelector(selector)
@@ -241,7 +239,7 @@
                 .withPriority(fwd.priority())
                 .makePermanent()
                 .forDevice(deviceId)
-                .forTable(FabricConstants.FABRIC_INGRESS_FORWARDING_UNICAST_V4)
+                .forTable(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4)
                 .build();
 
         resultBuilder.addFlowRule(flowRule);
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java
index 0349cc7..65e3a25 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java
@@ -49,22 +49,12 @@
     /**
      * IPv4 unicast, with EtherType and IPv4 unicast destination address.
      */
-    IPV4_UNICAST,
-
-    /**
-     * IPv4 multicast, with EtherType and IPv4 multicast destination address.
-     */
-    IPV4_MULTICAST,
+    IPV4_ROUTING,
 
     /**
      * IPv6 unicast, with EtherType and IPv6 unicast destination address.
      */
-    IPV6_UNICAST,
-
-    /**
-     * IPv6 multicast, with EtherType and IPv6 multicast destination address.
-     */
-    IPV6_MULTICAST,
+    IPV6_ROUTING,
 
     /**
      * MPLS, with EtherType, MPLS label and MPLS BOS(true) criterion.
@@ -101,10 +91,10 @@
             ImmutableMap.<Set<Criterion.Type>, ForwardingFunctionType>builder()
                     .put(L2_UNI_CRITERIA_TYPE, L2_UNICAST)
                     .put(L2_BRC_CRITERIA_TYPE, L2_BROADCAST)
-                    .put(IPV4_UNI_CRITERIA_TYPE, IPV4_UNICAST)
-                    .put(IPV4_MCAST_CRITERIA_TYPE, IPV4_MULTICAST)
-                    .put(IPV6_UNI_CRITERIA_TYPE, IPV6_UNICAST)
-                    .put(IPV6_MCAST_CRITERIA_TYPE, IPV6_MULTICAST)
+                    .put(IPV4_UNI_CRITERIA_TYPE, IPV4_ROUTING)
+                    .put(IPV4_MCAST_CRITERIA_TYPE, IPV4_ROUTING)
+                    .put(IPV6_UNI_CRITERIA_TYPE, IPV6_ROUTING)
+                    .put(IPV6_MCAST_CRITERIA_TYPE, IPV6_ROUTING)
                     .put(MPLS_UNI_CRITERIA_TYPE, MPLS)
                     .build();