eth_type moved outside ethernet header in fabric.p4

Change-Id: I3ae0813c5e8aba48767d5bb235fbbcfb75954010
(cherry picked from commit 693d76f189c59579837b559975c0ba767335dfc0)
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricConstants.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricConstants.java
index c10f3f5..952df6f 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricConstants.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricConstants.java
@@ -19,10 +19,10 @@
 import org.onosproject.net.pi.model.PiActionId;
 import org.onosproject.net.pi.model.PiActionParamId;
 import org.onosproject.net.pi.model.PiActionProfileId;
-import org.onosproject.net.pi.model.PiCounterId;
-import org.onosproject.net.pi.model.PiMatchFieldId;
 import org.onosproject.net.pi.model.PiMeterId;
 import org.onosproject.net.pi.model.PiPacketMetadataId;
+import org.onosproject.net.pi.model.PiCounterId;
+import org.onosproject.net.pi.model.PiMatchFieldId;
 import org.onosproject.net.pi.model.PiTableId;
 /**
  * Constants for fabric pipeline.
@@ -38,8 +38,6 @@
             PiMatchFieldId.of("ig_port");
     public static final PiMatchFieldId HDR_VLAN_IS_VALID =
             PiMatchFieldId.of("vlan_is_valid");
-    public static final PiMatchFieldId HDR_EG_PORT =
-            PiMatchFieldId.of("eg_port");
     public static final PiMatchFieldId HDR_IPV6_SRC_NET_ID =
             PiMatchFieldId.of("ipv6_src_net_id");
     public static final PiMatchFieldId HDR_C_TAG = PiMatchFieldId.of("c_tag");
@@ -47,8 +45,6 @@
             PiMatchFieldId.of("ipv4_src");
     public static final PiMatchFieldId HDR_IPV6_DST =
             PiMatchFieldId.of("ipv6_dst");
-    public static final PiMatchFieldId HDR_IS_MPLS =
-            PiMatchFieldId.of("is_mpls");
     public static final PiMatchFieldId HDR_L4_DPORT =
             PiMatchFieldId.of("l4_dport");
     public static final PiMatchFieldId HDR_PPPOE_CODE =
@@ -72,6 +68,8 @@
             PiMatchFieldId.of("eth_type");
     public static final PiMatchFieldId HDR_NEXT_ID =
             PiMatchFieldId.of("next_id");
+    public static final PiMatchFieldId HDR_IP_ETH_TYPE =
+            PiMatchFieldId.of("ip_eth_type");
     public static final PiMatchFieldId HDR_L4_SPORT =
             PiMatchFieldId.of("l4_sport");
     public static final PiMatchFieldId HDR_ICMP_CODE =
@@ -88,10 +86,8 @@
             PiMatchFieldId.of("line_id");
     public static final PiMatchFieldId HDR_IPV4_DSCP =
             PiMatchFieldId.of("ipv4_dscp");
-    public static final PiMatchFieldId HDR_IS_IPV4 =
-            PiMatchFieldId.of("is_ipv4");
-    public static final PiMatchFieldId HDR_IS_IPV6 =
-            PiMatchFieldId.of("is_ipv6");
+    public static final PiMatchFieldId HDR_EG_PORT =
+            PiMatchFieldId.of("eg_port");
     public static final PiMatchFieldId HDR_GTP_IPV4_DST =
             PiMatchFieldId.of("gtp_ipv4_dst");
     public static final PiMatchFieldId HDR_INT_IS_VALID =
@@ -181,8 +177,8 @@
             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_ROUTING_V4_COUNTER =
-            PiCounterId.of("FabricIngress.forwarding.routing_v4_counter");
+    public static final PiCounterId FABRIC_INGRESS_NEXT_HASHED_COUNTER =
+            PiCounterId.of("FabricIngress.next.hashed_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_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SOURCE_COUNTER_INT_SOURCE =
@@ -205,8 +201,6 @@
             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 =
-            PiCounterId.of("FabricIngress.next.hashed_counter");
     // Action IDs
     public static final PiActionId FABRIC_INGRESS_NEXT_SET_NEXT_ID_XCONNECT =
             PiActionId.of("FabricIngress.next.set_next_id_xconnect");
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/AbstractObjectiveTranslator.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/AbstractObjectiveTranslator.java
index 5b9671f..c630131 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/AbstractObjectiveTranslator.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/AbstractObjectiveTranslator.java
@@ -70,12 +70,18 @@
     public FlowRule flowRule(T obj, PiTableId tableId, TrafficSelector selector,
                              TrafficTreatment treatment)
             throws FabricPipelinerException {
+        return flowRule(obj, tableId, selector, treatment, obj.priority());
+    }
+
+    public FlowRule flowRule(T obj, PiTableId tableId, TrafficSelector selector,
+                             TrafficTreatment treatment, Integer priority)
+            throws FabricPipelinerException {
         return DefaultFlowRule.builder()
                 .withSelector(selector)
                 .withTreatment(mapTreatmentToPiIfNeeded(treatment, tableId))
                 .forTable(tableId)
                 .makePermanent()
-                .withPriority(obj.priority())
+                .withPriority(priority)
                 .forDevice(deviceId)
                 .fromApp(obj.appId())
                 .build();
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java
index d682d8c..a6f0e81 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java
@@ -17,7 +17,6 @@
 package org.onosproject.pipelines.fabric.impl.behaviour.pipeliner;
 
 import com.google.common.collect.Lists;
-import org.onlab.packet.EthType;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -60,6 +59,8 @@
     private static final byte[] ONE = new byte[]{1};
     private static final byte[] ZERO = new byte[]{0};
 
+    private static final short ETH_TYPE_EXACT_MASK = (short) 0xFFFF;
+
     private static final PiAction DENY = PiAction.builder()
             .withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
             .build();
@@ -163,7 +164,7 @@
         } else {
             final MacAddress dstMac = ethDstCriterion.mac();
             flowRules.addAll(ipFwdClassifierRules(inPort, dstMac, obj));
-            flowRules.add(mplsFwdClassifierRule(inPort, dstMac, obj));
+            flowRules.addAll(mplsFwdClassifierRules(inPort, dstMac, obj));
         }
 
         for (FlowRule f : flowRules) {
@@ -207,21 +208,58 @@
         return flowRules;
     }
 
-    private FlowRule mplsFwdClassifierRule(
+    private Collection<FlowRule> mplsFwdClassifierRules(
             PortNumber inPort, MacAddress dstMac, FilteringObjective obj)
             throws FabricPipelinerException {
-        return fwdClassifierRule(
-                inPort, Ethernet.MPLS_UNICAST, dstMac, null,
-                fwdClassifierTreatment(FWD_MPLS), obj);
+        // Forwarding classifier for MPLS is composed of 2 rules
+        // with higher priority wrt standard forwarding classifier rules,
+        // this is due to overlap on ternary matching.
+        TrafficTreatment treatment = fwdClassifierTreatment(FWD_MPLS);
+        final PiCriterion ethTypeMplsIpv4 = PiCriterion.builder()
+                .matchTernary(FabricConstants.HDR_ETH_TYPE,
+                              Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
+                .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
+                            Ethernet.TYPE_IPV4)
+                .build();
+        final TrafficSelector selectorMplsIpv4 = DefaultTrafficSelector.builder()
+                .matchInPort(inPort)
+                .matchPi(ethTypeMplsIpv4)
+                .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
+                .build();
+
+        final PiCriterion ethTypeMplsIpv6 = PiCriterion.builder()
+                .matchTernary(FabricConstants.HDR_ETH_TYPE,
+                              Ethernet.MPLS_UNICAST, ETH_TYPE_EXACT_MASK)
+                .matchExact(FabricConstants.HDR_IP_ETH_TYPE,
+                            Ethernet.TYPE_IPV6)
+                .build();
+        final TrafficSelector selectorMplsIpv6 = DefaultTrafficSelector.builder()
+                .matchInPort(inPort)
+                .matchPi(ethTypeMplsIpv6)
+                .matchEthDstMasked(dstMac, MacAddress.EXACT_MASK)
+                .build();
+
+        return List.of(
+                flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
+                         selectorMplsIpv4, treatment, obj.priority() + 1),
+                flowRule(obj, FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER,
+                         selectorMplsIpv6, treatment, obj.priority() + 1)
+        );
     }
 
     private FlowRule fwdClassifierRule(
             PortNumber inPort, short ethType, MacAddress dstMac, MacAddress dstMacMask,
             TrafficTreatment treatment, FilteringObjective obj)
             throws FabricPipelinerException {
+        // Match on ip_eth_type that is the eth_type of the L3 protocol.
+        // i.e., if the packet has an IP header, ip_eth_type should
+        // contain the corresponding eth_type (for IPv4 or IPv6)
+        final PiCriterion ethTypeCriterion = PiCriterion.builder()
+                .matchExact(FabricConstants.HDR_IP_ETH_TYPE, ethType)
+                .build();
         final TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchInPort(inPort)
-                .matchPi(mapEthTypeFwdClassifier(ethType))
+                .matchPi(ethTypeCriterion)
                 .matchEthDstMasked(dstMac, dstMacMask == null
                         ? MacAddress.EXACT_MASK : dstMacMask)
                 .build();
@@ -241,38 +279,4 @@
                 .build();
 
     }
-
-    static PiCriterion mapEthTypeFwdClassifier(short ethType) {
-        // Map the Ethernet type to the validity bits of the fabric pipeline
-        switch (EthType.EtherType.lookup(ethType)) {
-            case IPV4: {
-                return PiCriterion.builder()
-                        .matchExact(FabricConstants.HDR_IS_IPV4, ONE)
-                        .matchExact(FabricConstants.HDR_IS_IPV6, ZERO)
-                        .matchExact(FabricConstants.HDR_IS_MPLS, ZERO)
-                        .build();
-            }
-            case IPV6: {
-                return PiCriterion.builder()
-                        .matchExact(FabricConstants.HDR_IS_IPV4, ZERO)
-                        .matchExact(FabricConstants.HDR_IS_IPV6, ONE)
-                        .matchExact(FabricConstants.HDR_IS_MPLS, ZERO)
-                        .build();
-            }
-            case MPLS_UNICAST: {
-                return PiCriterion.builder()
-                        .matchExact(FabricConstants.HDR_IS_IPV4, ZERO)
-                        .matchExact(FabricConstants.HDR_IS_IPV6, ZERO)
-                        .matchExact(FabricConstants.HDR_IS_MPLS, ONE)
-                        .build();
-            }
-            default: {
-                return PiCriterion.builder()
-                        .matchExact(FabricConstants.HDR_IS_IPV4, ZERO)
-                        .matchExact(FabricConstants.HDR_IS_IPV6, ZERO)
-                        .matchExact(FabricConstants.HDR_IS_MPLS, ZERO)
-                        .build();
-            }
-        }
-    }
 }