Refactor fabric.p4 INT support to allow compilation on more P4 targets

Also use constant entries for instruction mask tables to avoid
programming them at runtime.

Change-Id: Ia1ab1ecd42a433daec171f9a30bcdba3b8484061
diff --git a/pipelines/fabric/src/main/resources/include/control/packetio.p4 b/pipelines/fabric/src/main/resources/include/control/packetio.p4
index 1086dac..a77d82a 100644
--- a/pipelines/fabric/src/main/resources/include/control/packetio.p4
+++ b/pipelines/fabric/src/main/resources/include/control/packetio.p4
@@ -26,6 +26,7 @@
             standard_metadata.egress_spec = hdr.packet_out.egress_port;
             hdr.packet_out.setInvalid();
             fabric_metadata.is_controller_packet_out = _TRUE;
+            // No need for ingress processing, straight to egress.
             exit;
         }
     }
@@ -41,7 +42,7 @@
     }
     apply {
         if (fabric_metadata.is_controller_packet_out == _TRUE) {
-            // No need to process through the rest of the pipeline.
+            // Transmit right away.
             exit;
         }
         if (standard_metadata.egress_port == CPU_PORT) {
diff --git a/pipelines/fabric/src/main/resources/include/define.p4 b/pipelines/fabric/src/main/resources/include/define.p4
index 77808bd..26d3167 100644
--- a/pipelines/fabric/src/main/resources/include/define.p4
+++ b/pipelines/fabric/src/main/resources/include/define.p4
@@ -19,6 +19,10 @@
 
 #define MAX_PORTS 511
 
+#if defined(WITH_INT_SOURCE) || defined(WITH_INT_TRANSIT) || defined(WITH_INT_SINK)
+#define WITH_INT
+#endif
+
 #ifndef _BOOL
 #define _BOOL bool
 #endif
@@ -68,8 +72,6 @@
 typedef bit<48> mac_addr_t;
 typedef bit<16> group_id_t;
 typedef bit<12> vlan_id_t;
-typedef bit<48> timestamp_t;
-typedef bit<32> switch_id_t;
 typedef bit<32> ipv4_addr_t;
 typedef bit<16> l4_port_t;
 
@@ -124,7 +126,10 @@
 /* indicate INT at LSB of DSCP */
 const bit<6> INT_DSCP = 0x1;
 
-const bit<8> INT_HEADER_LEN_WORD = 4;
+// Length of the whole INT header,
+// including shim and tail, excluding metadata stack.
+const bit<8> INT_HEADER_LEN_WORDS = 4;
+const bit<16> INT_HEADER_LEN_BYTES = 16;
 
 const bit<8> CPU_MIRROR_SESSION_ID = 250;
 const bit<32> REPORT_MIRROR_SESSION_ID = 500;
diff --git a/pipelines/fabric/src/main/resources/include/header.p4 b/pipelines/fabric/src/main/resources/include/header.p4
index 5591c11..46fa022 100644
--- a/pipelines/fabric/src/main/resources/include/header.p4
+++ b/pipelines/fabric/src/main/resources/include/header.p4
@@ -18,6 +18,7 @@
 #define __HEADER__
 
 #include "define.p4"
+#include "int/int_header.p4"
 
 @controller_header("packet_in")
 header packet_in_header_t {
@@ -147,122 +148,6 @@
 }
 #endif // WITH_SPGW
 
-#ifdef WITH_INT
-// Report Telemetry Headers
-header report_fixed_header_t {
-    bit<4>  ver;
-    bit<4>  nproto;
-    bit<1>  d;
-    bit<1>  q;
-    bit<1>  f;
-    bit<15> rsvd;
-    bit<6>  hw_id;
-    bit<32> seq_no;
-    bit<32> ingress_tstamp;
-}
-
-// Telemetry drop report header
-header drop_report_header_t {
-    bit<32> switch_id;
-    bit<16> ingress_port_id;
-    bit<16> egress_port_id;
-    bit<8>  queue_id;
-    bit<8>  drop_reason;
-    bit<16> pad;
-}
-
-// Switch Local Report Header
-header local_report_header_t {
-    bit<32> switch_id;
-    bit<16> ingress_port_id;
-    bit<16> egress_port_id;
-    bit<8>  queue_id;
-    bit<24> queue_occupancy;
-    bit<32> egress_tstamp;
-}
-
-header_union local_report_t {
-    drop_report_header_t drop_report_header;
-    local_report_header_t local_report_header;
-}
-
-// INT headers
-header int_header_t {
-    bit<2>  ver;
-    bit<2>  rep;
-    bit<1>  c;
-    bit<1>  e;
-    bit<5>  rsvd1;
-    bit<5>  ins_cnt;
-    bit<8>  max_hop_cnt;
-    bit<8>  total_hop_cnt;
-    bit<4>  instruction_mask_0003; /* split the bits for lookup */
-    bit<4>  instruction_mask_0407;
-    bit<4>  instruction_mask_0811;
-    bit<4>  instruction_mask_1215;
-    bit<16> rsvd2;
-}
-
-// INT meta-value headers - different header for each value type
-header int_switch_id_t {
-    bit<32> switch_id;
-}
-header int_port_ids_t {
-    bit<16> ingress_port_id;
-    bit<16> egress_port_id;
-}
-header int_hop_latency_t {
-    bit<32> hop_latency;
-}
-header int_q_occupancy_t {
-    bit<8> q_id;
-    bit<24> q_occupancy;
-}
-header int_ingress_tstamp_t {
-    bit<32> ingress_tstamp;
-}
-header int_egress_tstamp_t {
-    bit<32> egress_tstamp;
-}
-header int_q_congestion_t {
-    bit<8> q_id;
-    bit<24> q_congestion;
-}
-header int_egress_port_tx_util_t {
-    bit<32> egress_port_tx_util;
-}
-
-header int_data_t {
-    // Maximum int metadata stack size in bits:
-    // (0xFF -4) * 32 (excluding INT shim header, tail header and INT header)
-    varbit<8032> data;
-}
-
-/* INT shim header for TCP/UDP */
-header intl4_shim_t {
-    bit<8> int_type;
-    bit<8> rsvd1;
-    bit<8> len;
-    bit<8> rsvd2;
-}
-/* INT tail header for TCP/UDP */
-header intl4_tail_t {
-    bit<8> next_proto;
-    bit<16> dest_port;
-    bit<8> dscp;
-}
-
-struct int_metadata_t {
-    switch_id_t switch_id;
-    bit<16> insert_byte_cnt;
-    bit<1>  source;
-    bit<1>  sink;
-    bit<8>  mirror_id;
-    bit<16> flow_id;
-    bit<8>  metadata_len;
-}
-#endif // WITH_INT
-
 //Custom metadata definition
 struct fabric_metadata_t {
     fwd_type_t fwd_type;
@@ -279,7 +164,6 @@
 #endif // WITH_SPGW
 #ifdef WITH_INT
     int_metadata_t int_meta;
-    bool compute_checksum;
 #endif // WITH_INT
 }
 
@@ -304,18 +188,19 @@
     icmp_t icmp;
     packet_out_header_t packet_out;
     packet_in_header_t packet_in;
-#ifdef WITH_INT
-    // INT Report Encapsulation
+#ifdef WITH_INT_SINK
+    // INT Report encap
     ethernet_t report_ethernet;
     ipv4_t report_ipv4;
     udp_t report_udp;
-    // INT Report Headers
+    // INT Report header (support only fixed)
     report_fixed_header_t report_fixed_header;
-    local_report_t report_local;
+    // local_report_t report_local;
+#endif // WITH_INT_SINK
+#ifdef WITH_INT
     // INT specific headers
     intl4_shim_t intl4_shim;
     int_header_t int_header;
-    int_data_t int_data;
     int_switch_id_t int_switch_id;
     int_port_ids_t int_port_ids;
     int_hop_latency_t int_hop_latency;
@@ -324,6 +209,7 @@
     int_egress_tstamp_t int_egress_tstamp;
     int_q_congestion_t int_q_congestion;
     int_egress_port_tx_util_t int_egress_tx_util;
+    int_data_t int_data;
     intl4_tail_t intl4_tail;
 #endif //WITH_INT
 }
diff --git a/pipelines/fabric/src/main/resources/include/int/int_header.p4 b/pipelines/fabric/src/main/resources/include/int/int_header.p4
new file mode 100644
index 0000000..f339995
--- /dev/null
+++ b/pipelines/fabric/src/main/resources/include/int/int_header.p4
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __INT_HEADER__
+#define __INT_HEADER__
+
+#include "../define.p4"
+
+struct int_metadata_t {
+    _BOOL   source;
+    _BOOL   transit;
+    _BOOL   sink;
+    bit<32> switch_id;
+    bit<8>  new_words;
+    bit<16> new_bytes;
+}
+
+// INT headers - 8 bytes
+header int_header_t {
+    bit<2>  ver;
+    bit<2>  rep;
+    bit<1>  c;
+    bit<1>  e;
+    bit<5>  rsvd1;
+    bit<5>  ins_cnt;
+    bit<8>  max_hop_cnt;
+    bit<8>  total_hop_cnt;
+    bit<4>  instruction_mask_0003; /* split the bits for lookup */
+    bit<4>  instruction_mask_0407;
+    bit<4>  instruction_mask_0811;
+    bit<4>  instruction_mask_1215;
+    bit<16> rsvd2;
+}
+
+// INT shim header for TCP/UDP - 4 bytes
+header intl4_shim_t {
+    bit<8> int_type;
+    bit<8> rsvd1;
+    bit<8> len_words; // 4-byte words.
+    bit<8> rsvd2;
+}
+// INT tail header for TCP/UDP - 4 bytes
+header intl4_tail_t {
+    bit<8> next_proto;
+    bit<16> dest_port;
+    bit<2> padding;
+    bit<6> dscp;
+}
+
+header int_data_t {
+    // Maximum int metadata stack size in bits:
+    // (0xFF -4) * 32 (excluding INT shim header, tail header and INT header)
+    varbit<8032> data;
+}
+
+#ifdef WITH_INT_TRANSIT
+// INT meta-value headers - 4 bytes each
+// Different header for each value type
+header int_switch_id_t {
+    bit<32> switch_id;
+}
+header int_port_ids_t {
+    bit<16> ingress_port_id;
+    bit<16> egress_port_id;
+}
+header int_hop_latency_t {
+    bit<32> hop_latency;
+}
+header int_q_occupancy_t {
+    bit<8> q_id;
+    bit<24> q_occupancy;
+}
+header int_ingress_tstamp_t {
+    bit<32> ingress_tstamp;
+}
+header int_egress_tstamp_t {
+    bit<32> egress_tstamp;
+}
+header int_q_congestion_t {
+    bit<8> q_id;
+    bit<24> q_congestion;
+}
+header int_egress_port_tx_util_t {
+    bit<32> egress_port_tx_util;
+}
+#endif // WITH_INT_TRANSIT
+
+#ifdef WITH_INT_SINK
+// Report Telemetry Headers
+header report_fixed_header_t {
+    bit<4>  ver;
+    bit<4>  nproto;
+    bit<1>  d;
+    bit<1>  q;
+    bit<1>  f;
+    bit<15> rsvd;
+    bit<6>  hw_id;
+    bit<32> seq_no;
+    bit<32> ingress_tstamp;
+}
+
+// Telemetry drop report header
+header drop_report_header_t {
+    bit<32> switch_id;
+    bit<16> ingress_port_id;
+    bit<16> egress_port_id;
+    bit<8>  queue_id;
+    bit<8>  drop_reason;
+    bit<16> pad;
+}
+
+// Switch Local Report Header
+header local_report_header_t {
+    bit<32> switch_id;
+    bit<16> ingress_port_id;
+    bit<16> egress_port_id;
+    bit<8>  queue_id;
+    bit<24> queue_occupancy;
+    bit<32> egress_tstamp;
+}
+
+header_union local_report_t {
+    drop_report_header_t drop_report_header;
+    local_report_header_t local_report_header;
+}
+#endif // WITH_INT_SINK
+
+#endif
diff --git a/pipelines/fabric/src/main/resources/include/int/int_main.p4 b/pipelines/fabric/src/main/resources/include/int/int_main.p4
new file mode 100644
index 0000000..ef81cc9
--- /dev/null
+++ b/pipelines/fabric/src/main/resources/include/int/int_main.p4
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* -*- P4_16 -*- */
+#ifndef __INT_MAIN__
+#define __INT_MAIN__
+
+#ifdef WITH_INT_SOURCE
+#include "int_source.p4"
+#endif // WITH_INT_SOURCE
+
+#ifdef WITH_INT_TRANSIT
+#include "int_transit.p4"
+#endif // WITH_INT_TRANSIT
+
+#ifdef WITH_INT_SINK
+#include "int_sink.p4"
+#include "int_report.p4"
+#endif // WITH_INT_SINK
+
+control process_set_source_sink (
+    inout parsed_headers_t hdr,
+    inout fabric_metadata_t fabric_metadata,
+    inout standard_metadata_t standard_metadata) {
+
+    direct_counter(CounterType.packets_and_bytes) counter_set_source;
+
+    action int_set_source () {
+        fabric_metadata.int_meta.source = _TRUE;
+        counter_set_source.count();
+    }
+
+    table tb_set_source {
+        key = {
+            standard_metadata.ingress_port: exact;
+        }
+        actions = {
+            int_set_source;
+        }
+        counters = counter_set_source;
+        size = MAX_PORTS;
+    }
+
+#ifdef WITH_INT_SINK
+    direct_counter(CounterType.packets_and_bytes) counter_set_sink;
+
+    action int_set_sink () {
+        fabric_metadata.int_meta.sink = _TRUE;
+        counter_set_sink.count();
+    }
+
+    table tb_set_sink {
+        key = {
+            standard_metadata.egress_spec: exact;
+        }
+        actions = {
+            int_set_sink;
+        }
+        counters = counter_set_sink;
+        size = MAX_PORTS;
+    }
+#endif // WITH_INT_SINK
+
+    apply {
+        tb_set_source.apply();
+
+#ifdef WITH_INT_SINK
+        tb_set_sink.apply();
+        if(fabric_metadata.int_meta.sink == _TRUE) {
+            // FIXME: this works only on BMv2
+            #ifdef __TARGET_BMV2__
+            clone(CloneType.I2E, REPORT_MIRROR_SESSION_ID);
+            #endif
+        }
+#endif // WITH_INT_SINK
+    }
+}
+
+control process_int_main (
+    inout parsed_headers_t hdr,
+    inout fabric_metadata_t fabric_metadata,
+    inout standard_metadata_t standard_metadata) {
+
+    apply {
+        if (standard_metadata.ingress_port != CPU_PORT &&
+            standard_metadata.egress_port != CPU_PORT &&
+            (hdr.udp.isValid() || hdr.tcp.isValid())) {
+#ifdef WITH_INT_SOURCE
+            if (fabric_metadata.int_meta.source == _TRUE) {
+                process_int_source.apply(hdr, fabric_metadata, standard_metadata);
+            }
+#endif // WITH_INT_SOURCE
+            if(hdr.int_header.isValid()) {
+#ifdef WITH_INT_TRANSIT
+                process_int_transit.apply(hdr, fabric_metadata, standard_metadata);
+#endif // WITH_INT_TRANSIT
+#ifdef WITH_INT_SINK
+                if (standard_metadata.instance_type == PKT_INSTANCE_TYPE_INGRESS_CLONE) {
+                    /* send int report */
+                    process_int_report.apply(hdr, fabric_metadata, standard_metadata);
+                }
+                if (fabric_metadata.int_meta.sink == _TRUE) {
+                    // int sink
+                    process_int_sink.apply(hdr, fabric_metadata);
+                }
+#endif // WITH_INT_SINK
+            }
+        }
+    }
+}
+#endif
diff --git a/pipelines/fabric/src/main/resources/include/int_report.p4 b/pipelines/fabric/src/main/resources/include/int/int_report.p4
similarity index 95%
rename from pipelines/fabric/src/main/resources/include/int_report.p4
rename to pipelines/fabric/src/main/resources/include/int/int_report.p4
index 6d7c29d..9326375 100644
--- a/pipelines/fabric/src/main/resources/include/int_report.p4
+++ b/pipelines/fabric/src/main/resources/include/int/int_report.p4
@@ -40,8 +40,7 @@
         // TODO how save a variable and increment
         hdr.report_fixed_header.seq_no = 0;
         //TODO how to get timestamp from ingress ns
-        hdr.report_fixed_header.ingress_tstamp =
-        (bit<32>) standard_metadata.enq_timestamp;
+        hdr.report_fixed_header.ingress_tstamp = (bit<32>) standard_metadata.enq_timestamp;
     }
 
     action do_report_encapsulation(mac_addr_t src_mac, mac_addr_t mon_mac, ipv4_addr_t src_ip,
@@ -77,7 +76,6 @@
         hdr.report_udp.len =  (bit<16>) UDP_HEADER_LEN + (bit<16>) REPORT_FIXED_HEADER_LEN +
                                     (bit<16>) ETH_HEADER_LEN + hdr.ipv4.total_len;
 
-        fabric_metadata.compute_checksum = true;
         add_report_fixed_header();
     }
 
diff --git a/pipelines/fabric/src/main/resources/include/int_sink.p4 b/pipelines/fabric/src/main/resources/include/int/int_sink.p4
similarity index 83%
rename from pipelines/fabric/src/main/resources/include/int_sink.p4
rename to pipelines/fabric/src/main/resources/include/int/int_sink.p4
index 4c272d6..6c64e32 100644
--- a/pipelines/fabric/src/main/resources/include/int_sink.p4
+++ b/pipelines/fabric/src/main/resources/include/int/int_sink.p4
@@ -20,17 +20,18 @@
 
 control process_int_sink (
     inout parsed_headers_t hdr,
-    inout fabric_metadata_t fabric_metadata,
-    inout standard_metadata_t standard_metadata) {
+    inout fabric_metadata_t fabric_metadata) {
+
     action restore_header () {
         hdr.udp.dst_port = hdr.intl4_tail.dest_port;
-        hdr.ipv4.dscp = (bit<6>)hdr.intl4_tail.dscp;
+        hdr.ipv4.dscp = hdr.intl4_tail.dscp;
     }
 
     action int_sink() {
         // restore length fields of IPv4 header and UDP header
-        hdr.ipv4.total_len = hdr.ipv4.total_len - (bit<16>)(hdr.intl4_shim.len << 2);
-        hdr.udp.len = hdr.udp.len - (bit<16>)(hdr.intl4_shim.len << 2);
+        bit<16> len_bytes = (bit<16>) (hdr.intl4_shim.len_words << 5w2);
+        hdr.ipv4.total_len = hdr.ipv4.total_len - len_bytes;
+        hdr.udp.len = hdr.udp.len - len_bytes;
         // remove all the INT information from the packet
         hdr.int_header.setInvalid();
         hdr.int_data.setInvalid();
@@ -51,4 +52,4 @@
         int_sink();
     }
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/pipelines/fabric/src/main/resources/include/int_source.p4 b/pipelines/fabric/src/main/resources/include/int/int_source.p4
similarity index 65%
rename from pipelines/fabric/src/main/resources/include/int_source.p4
rename to pipelines/fabric/src/main/resources/include/int/int_source.p4
index 57c2b79..245fe7e 100644
--- a/pipelines/fabric/src/main/resources/include/int_source.p4
+++ b/pipelines/fabric/src/main/resources/include/int/int_source.p4
@@ -27,13 +27,12 @@
     direct_counter(CounterType.packets_and_bytes) counter_int_source;
 
     action int_source(bit<8> max_hop, bit<5> ins_cnt, bit<4> ins_mask0003, bit<4> ins_mask0407) {
-        // insert INT shim header
+        // Insert INT shim header.
         hdr.intl4_shim.setValid();
         // int_type: Hop-by-hop type (1) , destination type (2)
         hdr.intl4_shim.int_type = 1;
-        hdr.intl4_shim.len = INT_HEADER_LEN_WORD;
-
-        // insert INT header
+        hdr.intl4_shim.len_words = INT_HEADER_LEN_WORDS;
+        // Insert INT header.
         hdr.int_header.setValid();
         hdr.int_header.ver = 0;
         hdr.int_header.rep = 0;
@@ -47,20 +46,20 @@
         hdr.int_header.instruction_mask_0407 = ins_mask0407;
         hdr.int_header.instruction_mask_0811 = 0; // not supported
         hdr.int_header.instruction_mask_1215 = 0; // not supported
-
-        // insert INT tail header
+        // Insert INT tail header.
         hdr.intl4_tail.setValid();
         hdr.intl4_tail.next_proto = hdr.ipv4.protocol;
         hdr.intl4_tail.dest_port = fabric_metadata.l4_dst_port;
-        hdr.intl4_tail.dscp = (bit<8>) hdr.ipv4.dscp;
-
-        // add the header len (8 bytes) to total len
-        hdr.ipv4.total_len = hdr.ipv4.total_len + 16;
-        hdr.udp.len = hdr.udp.len + 16;
+        hdr.intl4_tail.dscp = hdr.ipv4.dscp;
+        // Update IP and UDP (if not valid we don't care) lens (in bytes).
+        hdr.ipv4.total_len = hdr.ipv4.total_len + INT_HEADER_LEN_BYTES;
+        hdr.udp.len = hdr.udp.len + INT_HEADER_LEN_BYTES;
     }
+
     action int_source_dscp(bit<8> max_hop, bit<5> ins_cnt, bit<4> ins_mask0003, bit<4> ins_mask0407) {
         int_source(max_hop, ins_cnt, ins_mask0003, ins_mask0407);
         hdr.ipv4.dscp = INT_DSCP;
+        counter_int_source.count();
     }
 
     table tb_int_source {
@@ -74,54 +73,10 @@
             int_source_dscp;
         }
         counters = counter_int_source;
-        size = 1024;
     }
 
     apply {
         tb_int_source.apply();
     }
 }
-
-control process_set_source_sink (
-    inout parsed_headers_t hdr,
-    inout fabric_metadata_t fabric_metadata,
-    inout standard_metadata_t standard_metadata) {
-
-    direct_counter(CounterType.packets_and_bytes) counter_set_source;
-    direct_counter(CounterType.packets_and_bytes) counter_set_sink;
-
-    action int_set_source () {
-        fabric_metadata.int_meta.source = 1;
-    }
-
-    action int_set_sink () {
-        fabric_metadata.int_meta.sink = 1;
-    }
-
-    table tb_set_source {
-        key = {
-            standard_metadata.ingress_port: exact;
-        }
-        actions = {
-            int_set_source;
-        }
-        counters = counter_set_source;
-        size = 256;
-    }
-    table tb_set_sink {
-        key = {
-            standard_metadata.egress_spec: exact;
-        }
-        actions = {
-            int_set_sink;
-        }
-        counters = counter_set_sink;
-        size = 256;
-    }
-
-    apply {
-        tb_set_source.apply();
-        tb_set_sink.apply();
-    }
-}
 #endif
diff --git a/pipelines/fabric/src/main/resources/include/int/int_transit.p4 b/pipelines/fabric/src/main/resources/include/int/int_transit.p4
new file mode 100644
index 0000000..4d4568b
--- /dev/null
+++ b/pipelines/fabric/src/main/resources/include/int/int_transit.p4
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* -*- P4_16 -*- */
+#ifndef __INT_TRANSIT__
+#define __INT_TRANSIT__
+control process_int_transit (
+    inout parsed_headers_t hdr,
+    inout fabric_metadata_t fmeta,
+    inout standard_metadata_t smeta) {
+
+    action init_metadata(bit<32> switch_id) {
+        fmeta.int_meta.transit = _TRUE;
+#ifdef _INT_INIT_METADATA
+        // Allow other targets to initialize INT metadata in their own way.
+        _INT_INIT_METADATA
+#else
+        fmeta.int_meta.switch_id = switch_id;
+#endif // _INT_INIT_METADATA
+    }
+
+#ifdef _INT_METADATA_ACTIONS
+    _INT_METADATA_ACTIONS
+#else
+    // Switch ID.
+    action int_set_header_0() {
+        hdr.int_switch_id.setValid();
+        hdr.int_switch_id.switch_id = fmeta.int_meta.switch_id;
+    }
+    // Port IDs.
+    action int_set_header_1() {
+        hdr.int_port_ids.setValid();
+        hdr.int_port_ids.ingress_port_id = (bit<16>) smeta.ingress_port;
+        hdr.int_port_ids.egress_port_id = (bit<16>) smeta.egress_port;
+    }
+    // Hop latency.
+    action int_set_header_2() {
+        hdr.int_hop_latency.setValid();
+        hdr.int_hop_latency.hop_latency = (bit<32>) smeta.deq_timedelta;
+    }
+    // Queue occupancy.
+    action int_set_header_3() {
+        hdr.int_q_occupancy.setValid();
+        // TODO: support queues in BMv2. ATM we assume only one.
+        hdr.int_q_occupancy.q_id = 8w0;
+        hdr.int_q_occupancy.q_occupancy = (bit<24>) smeta.deq_qdepth;
+    }
+    // Ingress timestamp.
+    action int_set_header_4() {
+        hdr.int_ingress_tstamp.setValid();
+        hdr.int_ingress_tstamp.ingress_tstamp = (bit<32>) smeta.enq_timestamp;
+    }
+    // Egress timestamp.
+    action int_set_header_5() {
+        hdr.int_egress_tstamp.setValid();
+        hdr.int_egress_tstamp.egress_tstamp = (bit<32>) smeta.enq_timestamp + (bit<32>) smeta.deq_timedelta;
+    }
+    // Queue congestion.
+    action int_set_header_6() {
+        hdr.int_q_congestion.setValid();
+        // TODO: support queue congestion.
+        hdr.int_q_congestion.q_id = 8w0;
+        hdr.int_q_congestion.q_congestion = 24w0;
+    }
+    // Egress port utilization.
+    action int_set_header_7() {
+        hdr.int_egress_tx_util.setValid();
+        // TODO: implement tx utilization support in BMv2.
+        hdr.int_egress_tx_util.egress_port_tx_util = 32w0;
+    }
+#endif // _INT_METADATA_ACTIONS
+
+    // Actions to keep track of the new metadata added.
+    action add_1() {
+        fmeta.int_meta.new_words = fmeta.int_meta.new_words + 1;
+        fmeta.int_meta.new_bytes = fmeta.int_meta.new_bytes + 4;
+    }
+
+    action add_2() {
+        fmeta.int_meta.new_words = fmeta.int_meta.new_words + 2;
+        fmeta.int_meta.new_bytes = fmeta.int_meta.new_bytes + 8;
+    }
+
+    action add_3() {
+        fmeta.int_meta.new_words = fmeta.int_meta.new_words + 3;
+        fmeta.int_meta.new_bytes = fmeta.int_meta.new_bytes + 12;
+    }
+
+    action add_4() {
+        fmeta.int_meta.new_words = fmeta.int_meta.new_words + 4;
+        fmeta.int_meta.new_bytes = fmeta.int_meta.new_bytes + 16;
+    }
+
+    // Action function for bits 0-3 combinations, 0 is msb, 3 is lsb.
+    // Each bit set indicates that corresponding INT header should be added.
+    action int_set_header_0003_i0() {
+    }
+    action int_set_header_0003_i1() {
+        int_set_header_3();
+        add_1();
+    }
+    action int_set_header_0003_i2() {
+        int_set_header_2();
+        add_1();
+    }
+    action int_set_header_0003_i3() {
+        int_set_header_3();
+        int_set_header_2();
+        add_2();
+    }
+    action int_set_header_0003_i4() {
+        int_set_header_1();
+        add_1();
+    }
+    action int_set_header_0003_i5() {
+        int_set_header_3();
+        int_set_header_1();
+        add_2();
+    }
+    action int_set_header_0003_i6() {
+        int_set_header_2();
+        int_set_header_1();
+        add_2();
+    }
+    action int_set_header_0003_i7() {
+        int_set_header_3();
+        int_set_header_2();
+        int_set_header_1();
+        add_3();
+    }
+    action int_set_header_0003_i8() {
+        int_set_header_0();
+        add_1();
+    }
+    action int_set_header_0003_i9() {
+        int_set_header_3();
+        int_set_header_0();
+        add_2();
+    }
+    action int_set_header_0003_i10() {
+        int_set_header_2();
+        int_set_header_0();
+        add_2();
+    }
+    action int_set_header_0003_i11() {
+        int_set_header_3();
+        int_set_header_2();
+        int_set_header_0();
+        add_3();
+    }
+    action int_set_header_0003_i12() {
+        int_set_header_1();
+        int_set_header_0();
+        add_2();
+    }
+    action int_set_header_0003_i13() {
+        int_set_header_3();
+        int_set_header_1();
+        int_set_header_0();
+        add_3();
+    }
+    action int_set_header_0003_i14() {
+        int_set_header_2();
+        int_set_header_1();
+        int_set_header_0();
+        add_3();
+    }
+    action int_set_header_0003_i15() {
+        int_set_header_3();
+        int_set_header_2();
+        int_set_header_1();
+        int_set_header_0();
+        add_4();
+    }
+
+    // Action function for bits 4-7 combinations, 4 is msb, 7 is lsb.
+    action int_set_header_0407_i0() {
+    }
+    action int_set_header_0407_i1() {
+        int_set_header_7();
+        add_1();
+    }
+    action int_set_header_0407_i2() {
+        int_set_header_6();
+        add_1();
+    }
+    action int_set_header_0407_i3() {
+        int_set_header_7();
+        int_set_header_6();
+        add_2();
+    }
+    action int_set_header_0407_i4() {
+        int_set_header_5();
+        add_1();
+    }
+    action int_set_header_0407_i5() {
+        int_set_header_7();
+        int_set_header_5();
+        add_2();
+    }
+    action int_set_header_0407_i6() {
+        int_set_header_6();
+        int_set_header_5();
+        add_2();
+    }
+    action int_set_header_0407_i7() {
+        int_set_header_7();
+        int_set_header_6();
+        int_set_header_5();
+        add_3();
+    }
+    action int_set_header_0407_i8() {
+        int_set_header_4();
+        add_1();
+    }
+    action int_set_header_0407_i9() {
+        int_set_header_7();
+        int_set_header_4();
+        add_2();
+    }
+    action int_set_header_0407_i10() {
+        int_set_header_6();
+        int_set_header_4();
+        add_2();
+    }
+    action int_set_header_0407_i11() {
+        int_set_header_7();
+        int_set_header_6();
+        int_set_header_4();
+        add_3();
+    }
+    action int_set_header_0407_i12() {
+        int_set_header_5();
+        int_set_header_4();
+        add_2();
+    }
+    action int_set_header_0407_i13() {
+        int_set_header_7();
+        int_set_header_5();
+        int_set_header_4();
+        add_3();
+    }
+    action int_set_header_0407_i14() {
+        int_set_header_6();
+        int_set_header_5();
+        int_set_header_4();
+        add_3();
+    }
+    action int_set_header_0407_i15() {
+        int_set_header_7();
+        int_set_header_6();
+        int_set_header_5();
+        int_set_header_4();
+        add_4();
+    }
+
+    // Default action used to set switch ID.
+    table tb_int_insert {
+        key = {}
+        actions = {
+            init_metadata;
+        }
+        size = 0;
+    }
+
+    // Table to process instruction bits 0-3.
+    table tb_int_inst_0003 {
+        key = {
+            hdr.int_header.instruction_mask_0003 : exact;
+        }
+        actions = {
+            int_set_header_0003_i0;
+            int_set_header_0003_i1;
+            int_set_header_0003_i2;
+            int_set_header_0003_i3;
+            int_set_header_0003_i4;
+            int_set_header_0003_i5;
+            int_set_header_0003_i6;
+            int_set_header_0003_i7;
+            int_set_header_0003_i8;
+            int_set_header_0003_i9;
+            int_set_header_0003_i10;
+            int_set_header_0003_i11;
+            int_set_header_0003_i12;
+            int_set_header_0003_i13;
+            int_set_header_0003_i14;
+            int_set_header_0003_i15;
+        }
+        size = 16;
+        const entries = {
+            (0x0) : int_set_header_0003_i0();
+            (0x1) : int_set_header_0003_i1();
+            (0x2) : int_set_header_0003_i2();
+            (0x3) : int_set_header_0003_i3();
+            (0x4) : int_set_header_0003_i4();
+            (0x5) : int_set_header_0003_i5();
+            (0x6) : int_set_header_0003_i6();
+            (0x7) : int_set_header_0003_i7();
+            (0x8) : int_set_header_0003_i8();
+            (0x9) : int_set_header_0003_i9();
+            (0xA) : int_set_header_0003_i10();
+            (0xB) : int_set_header_0003_i11();
+            (0xC) : int_set_header_0003_i12();
+            (0xD) : int_set_header_0003_i13();
+            (0xE) : int_set_header_0003_i14();
+            (0xF) : int_set_header_0003_i15();
+        }
+    }
+
+    // Table to process instruction bits 4-7.
+    table tb_int_inst_0407 {
+        key = {
+            hdr.int_header.instruction_mask_0407 : exact;
+        }
+        actions = {
+            int_set_header_0407_i0;
+            int_set_header_0407_i1;
+            int_set_header_0407_i2;
+            int_set_header_0407_i3;
+            int_set_header_0407_i4;
+            int_set_header_0407_i5;
+            int_set_header_0407_i6;
+            int_set_header_0407_i7;
+            int_set_header_0407_i8;
+            int_set_header_0407_i9;
+            int_set_header_0407_i10;
+            int_set_header_0407_i11;
+            int_set_header_0407_i12;
+            int_set_header_0407_i13;
+            int_set_header_0407_i14;
+            int_set_header_0407_i15;
+        }
+        size = 16;
+        const entries = {
+            (0x0) : int_set_header_0407_i0();
+            (0x1) : int_set_header_0407_i1();
+            (0x2) : int_set_header_0407_i2();
+            (0x3) : int_set_header_0407_i3();
+            (0x4) : int_set_header_0407_i4();
+            (0x5) : int_set_header_0407_i5();
+            (0x6) : int_set_header_0407_i6();
+            (0x7) : int_set_header_0407_i7();
+            (0x8) : int_set_header_0407_i8();
+            (0x9) : int_set_header_0407_i9();
+            (0xA) : int_set_header_0407_i10();
+            (0xB) : int_set_header_0407_i11();
+            (0xC) : int_set_header_0407_i12();
+            (0xD) : int_set_header_0407_i13();
+            (0xE) : int_set_header_0407_i14();
+            (0xF) : int_set_header_0407_i15();
+        }
+    }
+
+    apply {
+        tb_int_insert.apply();
+        if (fmeta.int_meta.transit == _FALSE) {
+            return;
+        }
+        tb_int_inst_0003.apply();
+        tb_int_inst_0407.apply();
+        // Increment hop cnt
+        hdr.int_header.total_hop_cnt = hdr.int_header.total_hop_cnt + 1;
+        // Update headers lengths.
+        if (hdr.ipv4.isValid()) {
+            hdr.ipv4.total_len = hdr.ipv4.total_len + fmeta.int_meta.new_bytes;
+        }
+        if (hdr.udp.isValid()) {
+            hdr.udp.len = hdr.udp.len + fmeta.int_meta.new_bytes;
+        }
+        if (hdr.intl4_shim.isValid()) {
+            hdr.intl4_shim.len_words = hdr.intl4_shim.len_words + fmeta.int_meta.new_words;
+        }
+    }
+}
+
+#endif
diff --git a/pipelines/fabric/src/main/resources/include/int_transit.p4 b/pipelines/fabric/src/main/resources/include/int_transit.p4
deleted file mode 100644
index 3f863e8..0000000
--- a/pipelines/fabric/src/main/resources/include/int_transit.p4
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* -*- P4_16 -*- */
-#ifndef __INT_TRANSIT__
-#define __INT_TRANSIT__
-control process_int_transit (
-    inout parsed_headers_t hdr,
-    inout fabric_metadata_t fabric_metadata,
-    inout standard_metadata_t standard_metadata) {
-
-    direct_counter(CounterType.packets_and_bytes) counter_int_insert;
-    direct_counter(CounterType.packets_and_bytes) counter_int_inst_0003;
-    direct_counter(CounterType.packets_and_bytes) counter_int_inst_0407;
-
-    action int_update_total_hop_cnt() {
-        hdr.int_header.total_hop_cnt = hdr.int_header.total_hop_cnt + 1;
-    }
-
-    action int_transit(switch_id_t switch_id) {
-        fabric_metadata.int_meta.switch_id = switch_id;
-        fabric_metadata.int_meta.insert_byte_cnt = (bit<16>) hdr.int_header.ins_cnt << 2;
-    }
-
-    /* Instr Bit 0 */
-    action int_set_header_0() { //switch_id
-        hdr.int_switch_id.setValid();
-        hdr.int_switch_id.switch_id = fabric_metadata.int_meta.switch_id;
-    }
-    action int_set_header_1() { //port_ids
-        hdr.int_port_ids.setValid();
-        hdr.int_port_ids.ingress_port_id =
-        (bit<16>) standard_metadata.ingress_port;
-        hdr.int_port_ids.egress_port_id =
-        (bit<16>) standard_metadata.egress_port;
-    }
-    action int_set_header_2() { //hop_latency
-        hdr.int_hop_latency.setValid();
-        hdr.int_hop_latency.hop_latency =
-        (bit<32>) standard_metadata.deq_timedelta;
-    }
-    action int_set_header_3() { //q_occupancy
-        // TODO: Support egress queue ID
-        hdr.int_q_occupancy.setValid();
-        hdr.int_q_occupancy.q_id =
-        0;
-        // (bit<8>) standard_metadata.egress_qid;
-        hdr.int_q_occupancy.q_occupancy =
-        (bit<24>) standard_metadata.deq_qdepth;
-    }
-    action int_set_header_4() { //ingress_tstamp
-        hdr.int_ingress_tstamp.setValid();
-        hdr.int_ingress_tstamp.ingress_tstamp =
-        (bit<32>) standard_metadata.enq_timestamp;
-    }
-    action int_set_header_5() { //egress_timestamp
-        hdr.int_egress_tstamp.setValid();
-        hdr.int_egress_tstamp.egress_tstamp =
-        (bit<32>) standard_metadata.enq_timestamp +
-        (bit<32>) standard_metadata.deq_timedelta;
-    }
-    action int_set_header_6() { //q_congestion
-        // TODO: implement queue congestion support in BMv2
-        // TODO: update egress queue ID
-        hdr.int_q_congestion.setValid();
-        hdr.int_q_congestion.q_id =
-        0;
-        // (bit<8>) standard_metadata.egress_qid;
-        hdr.int_q_congestion.q_congestion =
-        // (bit<24>) queueing_metadata.deq_congestion;
-        0;
-    }
-    action int_set_header_7() { //egress_port_tx_utilization
-        // TODO: implement tx utilization support in BMv2
-        hdr.int_egress_tx_util.setValid();
-        hdr.int_egress_tx_util.egress_port_tx_util =
-        // (bit<32>) queueing_metadata.tx_utilization;
-        0;
-    }
-
-    /* action function for bits 0-3 combinations, 0 is msb, 3 is lsb */
-    /* Each bit set indicates that corresponding INT header should be added */
-    action int_set_header_0003_i0() {
-    }
-    action int_set_header_0003_i1() {
-        int_set_header_3();
-    }
-    action int_set_header_0003_i2() {
-        int_set_header_2();
-    }
-    action int_set_header_0003_i3() {
-        int_set_header_3();
-        int_set_header_2();
-    }
-    action int_set_header_0003_i4() {
-        int_set_header_1();
-    }
-    action int_set_header_0003_i5() {
-        int_set_header_3();
-        int_set_header_1();
-    }
-    action int_set_header_0003_i6() {
-        int_set_header_2();
-        int_set_header_1();
-    }
-    action int_set_header_0003_i7() {
-        int_set_header_3();
-        int_set_header_2();
-        int_set_header_1();
-    }
-    action int_set_header_0003_i8() {
-        int_set_header_0();
-    }
-    action int_set_header_0003_i9() {
-        int_set_header_3();
-        int_set_header_0();
-    }
-    action int_set_header_0003_i10() {
-        int_set_header_2();
-        int_set_header_0();
-    }
-    action int_set_header_0003_i11() {
-        int_set_header_3();
-        int_set_header_2();
-        int_set_header_0();
-    }
-    action int_set_header_0003_i12() {
-        int_set_header_1();
-        int_set_header_0();
-    }
-    action int_set_header_0003_i13() {
-        int_set_header_3();
-        int_set_header_1();
-        int_set_header_0();
-    }
-    action int_set_header_0003_i14() {
-        int_set_header_2();
-        int_set_header_1();
-        int_set_header_0();
-    }
-    action int_set_header_0003_i15() {
-        int_set_header_3();
-        int_set_header_2();
-        int_set_header_1();
-        int_set_header_0();
-    }
-
-    /* action function for bits 4-7 combinations, 4 is msb, 7 is lsb */
-    action int_set_header_0407_i0() {
-    }
-    action int_set_header_0407_i1() {
-        int_set_header_7();
-    }
-    action int_set_header_0407_i2() {
-        int_set_header_6();
-    }
-    action int_set_header_0407_i3() {
-        int_set_header_7();
-        int_set_header_6();
-    }
-    action int_set_header_0407_i4() {
-        int_set_header_5();
-    }
-    action int_set_header_0407_i5() {
-        int_set_header_7();
-        int_set_header_5();
-    }
-    action int_set_header_0407_i6() {
-        int_set_header_6();
-        int_set_header_5();
-    }
-    action int_set_header_0407_i7() {
-        int_set_header_7();
-        int_set_header_6();
-        int_set_header_5();
-    }
-    action int_set_header_0407_i8() {
-        int_set_header_4();
-    }
-    action int_set_header_0407_i9() {
-        int_set_header_7();
-        int_set_header_4();
-    }
-    action int_set_header_0407_i10() {
-        int_set_header_6();
-        int_set_header_4();
-    }
-    action int_set_header_0407_i11() {
-        int_set_header_7();
-        int_set_header_6();
-        int_set_header_4();
-    }
-    action int_set_header_0407_i12() {
-        int_set_header_5();
-        int_set_header_4();
-    }
-    action int_set_header_0407_i13() {
-        int_set_header_7();
-        int_set_header_5();
-        int_set_header_4();
-    }
-    action int_set_header_0407_i14() {
-        int_set_header_6();
-        int_set_header_5();
-        int_set_header_4();
-    }
-    action int_set_header_0407_i15() {
-        int_set_header_7();
-        int_set_header_6();
-        int_set_header_5();
-        int_set_header_4();
-    }
-
-    table tb_int_insert {
-        key = {}
-        actions = {
-            int_transit;
-        }
-        counters = counter_int_insert;
-        size = 2;
-    }
-
-    /* Table to process instruction bits 0-3 */
-    table tb_int_inst_0003 {
-        key = {
-            hdr.int_header.instruction_mask_0003 : exact;
-        }
-        actions = {
-            int_set_header_0003_i0;
-            int_set_header_0003_i1;
-            int_set_header_0003_i2;
-            int_set_header_0003_i3;
-            int_set_header_0003_i4;
-            int_set_header_0003_i5;
-            int_set_header_0003_i6;
-            int_set_header_0003_i7;
-            int_set_header_0003_i8;
-            int_set_header_0003_i9;
-            int_set_header_0003_i10;
-            int_set_header_0003_i11;
-            int_set_header_0003_i12;
-            int_set_header_0003_i13;
-            int_set_header_0003_i14;
-            int_set_header_0003_i15;
-        }
-        counters = counter_int_inst_0003;
-        size = 16;
-    }
-
-    /* Table to process instruction bits 4-7 */
-    table tb_int_inst_0407 {
-        key = {
-            hdr.int_header.instruction_mask_0407 : exact;
-        }
-        actions = {
-            int_set_header_0407_i0;
-            int_set_header_0407_i1;
-            int_set_header_0407_i2;
-            int_set_header_0407_i3;
-            int_set_header_0407_i4;
-            int_set_header_0407_i5;
-            int_set_header_0407_i6;
-            int_set_header_0407_i7;
-            int_set_header_0407_i8;
-            int_set_header_0407_i9;
-            int_set_header_0407_i10;
-            int_set_header_0407_i11;
-            int_set_header_0407_i12;
-            int_set_header_0407_i13;
-            int_set_header_0407_i14;
-            int_set_header_0407_i15;
-        }
-        counters = counter_int_inst_0407;
-        size = 16;
-    }
-
-    apply {
-        tb_int_insert.apply();
-        tb_int_inst_0003.apply();
-        tb_int_inst_0407.apply();
-        int_update_total_hop_cnt();
-    }
-}
-
-control process_int_outer_encap (
-    inout parsed_headers_t hdr,
-    inout fabric_metadata_t fabric_metadata,
-    inout standard_metadata_t standard_metadata) {
-
-    action int_update_ipv4() {
-        hdr.ipv4.total_len = hdr.ipv4.total_len + fabric_metadata.int_meta.insert_byte_cnt;
-    }
-    action int_update_udp() {
-        hdr.udp.len = hdr.udp.len + fabric_metadata.int_meta.insert_byte_cnt;
-    }
-    action int_update_shim() {
-        hdr.intl4_shim.len = hdr.intl4_shim.len + (bit<8>)hdr.int_header.ins_cnt;
-    }
-
-    apply {
-        if (hdr.ipv4.isValid()) {
-            int_update_ipv4();
-        }
-        if (hdr.udp.isValid()) {
-            int_update_udp();
-        }
-        if (hdr.intl4_shim.isValid()) {
-            int_update_shim();
-        }
-    }
-}
-
-#endif
diff --git a/pipelines/fabric/src/main/resources/include/parser.p4 b/pipelines/fabric/src/main/resources/include/parser.p4
index 20c310c..3f77df9 100644
--- a/pipelines/fabric/src/main/resources/include/parser.p4
+++ b/pipelines/fabric/src/main/resources/include/parser.p4
@@ -25,6 +25,8 @@
 inout fabric_metadata_t fabric_metadata,
 inout standard_metadata_t standard_metadata) {
 
+    bit<6> last_ipv4_dscp = 0;
+
     state start {
         transition select(standard_metadata.ingress_port) {
             CPU_PORT: parse_packet_out;
@@ -82,6 +84,7 @@
     state parse_ipv4 {
         packet.extract(hdr.ipv4);
         fabric_metadata.ip_proto = hdr.ipv4.protocol;
+        last_ipv4_dscp = hdr.ipv4.dscp;
         //Need header verification?
         transition select(hdr.ipv4.protocol) {
             PROTO_TCP: parse_tcp;
@@ -114,10 +117,7 @@
         fabric_metadata.l4_src_port = hdr.tcp.src_port;
         fabric_metadata.l4_dst_port = hdr.tcp.dst_port;
 #ifdef WITH_INT
-        transition select(hdr.ipv4.isValid() && ((hdr.ipv4.dscp & INT_DSCP) == INT_DSCP)) {
-            true: parse_intl4_shim;
-            default: accept;
-        }
+        transition parse_int;
 #else
         transition accept;
 #endif // WITH_INT
@@ -127,19 +127,16 @@
         packet.extract(hdr.udp);
         fabric_metadata.l4_src_port = hdr.udp.src_port;
         fabric_metadata.l4_dst_port = hdr.udp.dst_port;
-#ifdef WITH_SPGW
         transition select(hdr.udp.dst_port) {
+#ifdef WITH_SPGW
             UDP_PORT_GTPU: parse_gtpu;
-            default: accept;
-        }
-#elif WITH_INT
-        transition select(hdr.ipv4.isValid() && (hdr.ipv4.dscp & INT_DSCP) == INT_DSCP) {
-            true: parse_intl4_shim;
-            default: accept;
-        }
+#endif // WITH_SPGW
+#ifdef WITH_INT
+            default: parse_int;
 #else
-        transition accept;
-#endif // WITH_SPGW, WITH_INT
+            default: accept;
+#endif // WITH_INT
+        }
     }
 
     state parse_icmp {
@@ -147,36 +144,6 @@
         transition accept;
     }
 
-#ifdef WITH_INT
-    state parse_intl4_shim {
-        packet.extract(hdr.intl4_shim);
-        transition parse_int_header;
-    }
-
-    state parse_int_header {
-        packet.extract(hdr.int_header);
-        // If there is no INT metadata but the INT header (and corresponding shim header
-        // and tail header) exists, default value of length field in shim header
-        // should be INT_HEADER_LEN_WORD.
-        fabric_metadata.int_meta.metadata_len = hdr.intl4_shim.len - INT_HEADER_LEN_WORD;
-        transition select (fabric_metadata.int_meta.metadata_len) {
-            0: parse_intl4_tail;
-            default: parse_int_data;
-        }
-    }
-
-    state parse_int_data {
-        // Parse INT metadata, not INT header, INT shim header and INT tail header
-        packet.extract(hdr.int_data, (bit<32>) ((hdr.intl4_shim.len - INT_HEADER_LEN_WORD) << 5));
-        transition parse_intl4_tail;
-    }
-
-    state parse_intl4_tail {
-        packet.extract(hdr.intl4_tail);
-        transition accept;
-    }
-#endif // WITH_INT
-
 #ifdef WITH_SPGW
     state parse_gtpu {
         transition select(hdr.ipv4.dst_addr[31:32-S1U_SGW_PREFIX_LEN]) {
@@ -196,6 +163,7 @@
 
     state parse_inner_ipv4 {
         packet.extract(hdr.inner_ipv4);
+        last_ipv4_dscp = hdr.inner_ipv4.dscp;
         transition select(hdr.inner_ipv4.protocol) {
             PROTO_TCP: parse_tcp;
             PROTO_UDP: parse_inner_udp;
@@ -209,26 +177,63 @@
         fabric_metadata.l4_src_port = hdr.inner_udp.src_port;
         fabric_metadata.l4_dst_port = hdr.inner_udp.dst_port;
 #ifdef WITH_INT
-        transition select(hdr.ipv4.isValid() && (hdr.ipv4.dscp & INT_DSCP) == INT_DSCP) {
-            true: parse_intl4_shim;
-            default: accept;
-        }
+        transition parse_int;
 #else
         transition accept;
 #endif // WITH_INT
     }
 #endif // WITH_SPGW
+
+#ifdef WITH_INT
+    state parse_int {
+        transition select(last_ipv4_dscp) {
+            INT_DSCP &&& INT_DSCP: parse_intl4_shim;
+            default: accept;
+        }
+    }
+
+    state parse_intl4_shim {
+        packet.extract(hdr.intl4_shim);
+        transition parse_int_header;
+    }
+
+    state parse_int_header {
+        packet.extract(hdr.int_header);
+        // If there is no INT metadata but the INT header (plus shim and tail)
+        // exists, default value of length field in shim header should be
+        // INT_HEADER_LEN_WORDS.
+        transition select (hdr.intl4_shim.len_words) {
+            INT_HEADER_LEN_WORDS: parse_intl4_tail;
+            default: parse_int_data;
+        }
+    }
+
+    state parse_int_data {
+#ifdef WITH_INT_SINK
+        // Parse INT metadata stack, but not tail
+        packet.extract(hdr.int_data, (bit<32>) (hdr.intl4_shim.len_words - INT_HEADER_LEN_WORDS) << 5);
+        transition parse_intl4_tail;
+#else // not interested in INT data
+        transition accept;
+#endif // WITH_INT_SINK
+    }
+
+    state parse_intl4_tail {
+        packet.extract(hdr.intl4_tail);
+        transition accept;
+    }
+#endif // WITH_INT
 }
 
 control FabricDeparser(packet_out packet, in parsed_headers_t hdr) {
     apply {
         packet.emit(hdr.packet_in);
-#ifdef WITH_INT
+#ifdef WITH_INT_SINK
         packet.emit(hdr.report_ethernet);
         packet.emit(hdr.report_ipv4);
         packet.emit(hdr.report_udp);
         packet.emit(hdr.report_fixed_header);
-#endif // WITH_INT
+#endif // WITH_INT_SINK
         packet.emit(hdr.ethernet);
         packet.emit(hdr.vlan_tag);
         packet.emit(hdr.mpls);
@@ -248,6 +253,7 @@
 #ifdef WITH_INT
         packet.emit(hdr.intl4_shim);
         packet.emit(hdr.int_header);
+#ifdef WITH_INT_TRANSIT
         packet.emit(hdr.int_switch_id);
         packet.emit(hdr.int_port_ids);
         packet.emit(hdr.int_hop_latency);
@@ -256,6 +262,7 @@
         packet.emit(hdr.int_egress_tstamp);
         packet.emit(hdr.int_q_congestion);
         packet.emit(hdr.int_egress_tx_util);
+#endif // WITH_INT_TRANSIT
         packet.emit(hdr.int_data);
         packet.emit(hdr.intl4_tail);
 #endif // WITH_INT