Merge branch 'master' into dev-karaf-4.2.1

Change-Id: I86b9d80581cd76a7c20e05201023090f9692d1ab
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 78cf071..07bb862 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
@@ -45,6 +45,8 @@
             PiMatchFieldId.of("hdr.vlan_tag.is_valid");
     public static final PiMatchFieldId HDR_ICMP_ICMP_CODE =
             PiMatchFieldId.of("hdr.icmp.icmp_code");
+    public static final PiMatchFieldId HDR_INT_HEADER_IS_VALID =
+            PiMatchFieldId.of("hdr.int_header.is_valid");
     public static final PiMatchFieldId HDR_ETHERNET_SRC_ADDR =
             PiMatchFieldId.of("hdr.ethernet.src_addr");
     public static final PiMatchFieldId HDR_ICMP_ICMP_TYPE =
@@ -82,36 +84,36 @@
             PiTableId.of("FabricIngress.forwarding.acl");
     public static final PiTableId FABRIC_INGRESS_NEXT_HASHED =
             PiTableId.of("FabricIngress.next.hashed");
+    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SOURCE_TB_INT_SOURCE =
+            PiTableId.of("FabricEgress.process_int_main.process_int_source.tb_int_source");
     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_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_TB_INT_INST_0407 =
+            PiTableId.of("FabricEgress.process_int_main.process_int_transit.tb_int_inst_0407");
+    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_TB_INT_INSERT =
+            PiTableId.of("FabricEgress.process_int_main.process_int_transit.tb_int_insert");
     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_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_TB_INT_INST_0003 =
+            PiTableId.of("FabricEgress.process_int_main.process_int_transit.tb_int_inst_0003");
     public static final PiTableId FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN =
             PiTableId.of("FabricIngress.filtering.ingress_port_vlan");
+    public static final PiTableId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_REPORT_TB_GENERATE_REPORT =
+            PiTableId.of("FabricEgress.process_int_main.process_int_report.tb_generate_report");
     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_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_NEXT_MULTICAST =
@@ -140,22 +142,16 @@
             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_EGRESS_PROCESS_INT_TRANSIT_COUNTER_INT_INST_0407 =
-            PiCounterId.of("FabricEgress.process_int_transit.counter_int_inst_0407");
+    public static final PiCounterId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SOURCE_COUNTER_INT_SOURCE =
+            PiCounterId.of("FabricEgress.process_int_main.process_int_source.counter_int_source");
     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_INGRESS_NEXT_SIMPLE_COUNTER =
             PiCounterId.of("FabricIngress.next.simple_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_EGRESS_EGRESS_NEXT_EGRESS_VLAN_COUNTER =
+            PiCounterId.of("FabricEgress.egress_next.egress_vlan_counter");
     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 =
@@ -165,145 +161,129 @@
     public static final PiCounterId FABRIC_INGRESS_NEXT_HASHED_COUNTER =
             PiCounterId.of("FabricIngress.next.hashed_counter");
     // Action IDs
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I14 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i14");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_PUNT_TO_CPU =
             PiActionId.of("FabricIngress.forwarding.punt_to_cpu");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I12 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i12");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I13 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i13");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I10 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i10");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I5 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i5");
     public static final PiActionId FABRIC_INGRESS_NEXT_MPLS_ROUTING_V6_SIMPLE =
             PiActionId.of("FabricIngress.next.mpls_routing_v6_simple");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I12 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i12");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_NOP_ROUTING_V4 =
             PiActionId.of("FabricIngress.forwarding.nop_routing_v4");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_UPDATE_TOTAL_HOP_CNT =
-            PiActionId.of("FabricEgress.process_int_transit.int_update_total_hop_cnt");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I10 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i10");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I11 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i11");
     public static final PiActionId FABRIC_INGRESS_FILTERING_NOP_INGRESS_PORT_VLAN =
             PiActionId.of("FabricIngress.filtering.nop_ingress_port_vlan");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I14 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i14");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I14 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i14");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_BRIDGING =
             PiActionId.of("FabricIngress.forwarding.set_next_id_bridging");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I15 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i15");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I2 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i2");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I5 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i5");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I4 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i4");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_SINK_INT_SINK =
-            PiActionId.of("FabricEgress.process_int_sink.int_sink");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I3 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i3");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I13 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i13");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I7 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i7");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SOURCE_INT_SOURCE_DSCP =
+            PiActionId.of("FabricEgress.process_int_main.process_int_source.int_source_dscp");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I0 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i0");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INIT_METADATA =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.init_metadata");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I14 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i14");
+    public static final PiActionId FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN =
+            PiActionId.of("FabricEgress.egress_next.pop_vlan");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I4 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i4");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I2 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i2");
     public static final PiActionId FABRIC_INGRESS_NEXT_SET_VLAN =
             PiActionId.of("FabricIngress.next.set_vlan");
-    public static final PiActionId FABRIC_EGRESS_PKT_IO_EGRESS_POP_VLAN =
-            PiActionId.of("FabricEgress.pkt_io_egress.pop_vlan");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I8 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i8");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I9 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i9");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I4 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i4");
     public static final PiActionId FABRIC_EGRESS_SPGW_EGRESS_GTPU_ENCAP =
             PiActionId.of("FabricEgress.spgw_egress.gtpu_encap");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I4 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i4");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I5 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i5");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I12 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i12");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I13 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i13");
     public static final PiActionId FABRIC_INGRESS_FILTERING_SET_VLAN =
             PiActionId.of("FabricIngress.filtering.set_vlan");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I11 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i11");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I0 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i0");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I1 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i1");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I11 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i11");
+    public static final PiActionId FABRIC_EGRESS_PKT_IO_EGRESS_POP_VLAN =
+            PiActionId.of("FabricEgress.pkt_io_egress.pop_vlan");
     public static final PiActionId FABRIC_INGRESS_NEXT_L3_ROUTING_SIMPLE =
             PiActionId.of("FabricIngress.next.l3_routing_simple");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I3 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i3");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I15 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i15");
     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_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I13 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i13");
     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_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I7 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i7");
     public static final PiActionId FABRIC_INGRESS_FILTERING_PUSH_INTERNAL_VLAN =
             PiActionId.of("FabricIngress.filtering.push_internal_vlan");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_CLONE_TO_CPU =
             PiActionId.of("FabricIngress.forwarding.clone_to_cpu");
     public static final PiActionId FABRIC_INGRESS_SPGW_INGRESS_GTPU_DECAP =
             PiActionId.of("FabricIngress.spgw_ingress.gtpu_decap");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I15 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i15");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I12 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i12");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_POP_MPLS_AND_NEXT =
             PiActionId.of("FabricIngress.forwarding.pop_mpls_and_next");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I10 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i10");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I11 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i11");
     public static final PiActionId DROP_NOW = PiActionId.of("drop_now");
     public static final PiActionId FABRIC_INGRESS_NEXT_L3_ROUTING_HASHED =
             PiActionId.of("FabricIngress.next.l3_routing_hashed");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_SOURCE_INT_SOURCE_DSCP =
-            PiActionId.of("FabricEgress.process_int_source.int_source_dscp");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_REPORT_DO_REPORT_ENCAPSULATION =
-            PiActionId.of("FabricEgress.process_int_report.do_report_encapsulation");
-    public static final PiActionId FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN =
-            PiActionId.of("FabricEgress.egress_next.pop_vlan");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I10 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i10");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I8 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i8");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I0 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i0");
     public static final PiActionId FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_INT_SET_SINK =
             PiActionId.of("FabricIngress.process_set_source_sink.int_set_sink");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_OUTER_ENCAP_INT_UPDATE_SHIM =
-            PiActionId.of("FabricEgress.process_int_outer_encap.int_update_shim");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SINK_INT_SINK =
+            PiActionId.of("FabricEgress.process_int_main.process_int_sink.int_sink");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I1 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i1");
     public static final PiActionId FABRIC_INGRESS_NEXT_MPLS_ROUTING_V4_HASHED =
             PiActionId.of("FabricIngress.next.mpls_routing_v4_hashed");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I1 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i1");
     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_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I3 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i3");
     public static final PiActionId NOP = PiActionId.of("nop");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_DROP =
             PiActionId.of("FabricIngress.forwarding.drop");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I6 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i6");
     public static final PiActionId FABRIC_INGRESS_NEXT_OUTPUT_SIMPLE =
             PiActionId.of("FabricIngress.next.output_simple");
     public static final PiActionId FABRIC_INGRESS_FILTERING_DROP =
             PiActionId.of("FabricIngress.filtering.drop");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_OUTER_ENCAP_INT_UPDATE_IPV4 =
-            PiActionId.of("FabricEgress.process_int_outer_encap.int_update_ipv4");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I8 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i8");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I9 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i9");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_SINK_RESTORE_HEADER =
-            PiActionId.of("FabricEgress.process_int_sink.restore_header");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SINK_RESTORE_HEADER =
+            PiActionId.of("FabricEgress.process_int_main.process_int_sink.restore_header");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I9 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i9");
     public static final PiActionId FABRIC_INGRESS_FILTERING_SET_FORWARDING_TYPE =
             PiActionId.of("FabricIngress.filtering.set_forwarding_type");
     public static final PiActionId FABRIC_INGRESS_NEXT_SET_VLAN_OUTPUT =
             PiActionId.of("FabricIngress.next.set_vlan_output");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I6 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i6");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I7 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i7");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I0 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i0");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I1 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0003_i1");
-    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 FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_REPORT_DO_REPORT_ENCAPSULATION =
+            PiActionId.of("FabricEgress.process_int_main.process_int_report.do_report_encapsulation");
     public static final PiActionId NO_ACTION = PiActionId.of("NoAction");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_TRANSIT =
-            PiActionId.of("FabricEgress.process_int_transit.int_transit");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I8 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i8");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I9 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i9");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I15 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0407_i15");
     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 =
@@ -312,10 +292,18 @@
             PiActionId.of("FabricIngress.next.mpls_routing_v6_hashed");
     public static final PiActionId FABRIC_INGRESS_NEXT_L3_ROUTING_VLAN =
             PiActionId.of("FabricIngress.next.l3_routing_vlan");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I2 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i2");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I3 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i3");
     public static final PiActionId FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ACL =
             PiActionId.of("FabricIngress.forwarding.set_next_id_acl");
-    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I6 =
-            PiActionId.of("FabricEgress.process_int_transit.int_set_header_0407_i6");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I5 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i5");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I6 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i6");
+    public static final PiActionId FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I7 =
+            PiActionId.of("FabricEgress.process_int_main.process_int_transit.int_set_header_0003_i7");
     // Action Param IDs
     public static final PiActionParamId DMAC = PiActionParamId.of("dmac");
     public static final PiActionParamId MON_IP = PiActionParamId.of("mon_ip");
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 b3f996d..2d5b280 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
@@ -36,12 +36,20 @@
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.pi.model.PiMatchFieldId;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
 import org.onosproject.net.pi.model.PiPipelineInterpreter;
 import org.onosproject.net.pi.model.PiTableId;
 import org.onosproject.net.pi.runtime.PiAction;
 import org.onosproject.net.pi.runtime.PiControlMetadata;
 import org.onosproject.net.pi.runtime.PiPacketOperation;
+import org.onosproject.net.pi.service.PiPipeconfService;
+import org.slf4j.Logger;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.nio.ByteBuffer;
 import java.util.Collection;
 import java.util.List;
@@ -51,9 +59,12 @@
 import static java.lang.String.format;
 import static java.util.stream.Collectors.toList;
 import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onosproject.net.PortNumber.CONTROLLER;
 import static org.onosproject.net.PortNumber.FLOOD;
 import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
 import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
+import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.CPU_PORT_TXT;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Interpreter for fabric pipeline.
@@ -61,6 +72,8 @@
 public class FabricInterpreter extends AbstractHandlerBehaviour
         implements PiPipelineInterpreter {
 
+    private final Logger log = getLogger(getClass());
+
     public static final int PORT_BITWIDTH = 9;
 
     private static final ImmutableBiMap<Integer, PiTableId> TABLE_ID_MAP =
@@ -134,6 +147,14 @@
                     .put(FabricConstants.HDR_ICMP_ICMP_CODE, Criterion.Type.ICMPV6_CODE)
                     .build();
 
+    private static final PiAction NOACTION = PiAction.builder().withId(
+            FabricConstants.NO_ACTION).build();
+
+    private static final ImmutableMap<PiTableId, PiAction> DEFAULT_ACTIONS =
+            ImmutableMap.<PiTableId, PiAction>builder()
+                    .put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4, NOACTION)
+                    .build();
+
     @Override
     public Optional<PiMatchFieldId> mapCriterionType(Criterion.Type type) {
         return Optional.ofNullable(CRITERION_MAP.get(type));
@@ -262,4 +283,60 @@
                     FabricConstants.INGRESS_PORT, deviceId, packetIn));
         }
     }
+
+    @Override
+    public Optional<PiAction> getOriginalDefaultAction(PiTableId tableId) {
+        return Optional.ofNullable(DEFAULT_ACTIONS.get(tableId));
+    }
+
+    @Override
+    public Optional<Integer> mapLogicalPortNumber(PortNumber port) {
+        if (!port.equals(CONTROLLER)) {
+            return Optional.empty();
+        }
+        // This is probably brittle, but needed to dynamically get the CPU port
+        // for different platforms.
+        final DeviceId deviceId = data().deviceId();
+        final PiPipeconfService pipeconfService = handler().get(
+                PiPipeconfService.class);
+        final PiPipeconfId pipeconfId = pipeconfService
+                .ofDevice(deviceId).orElse(null);
+        if (pipeconfId == null ||
+                !pipeconfService.getPipeconf(pipeconfId).isPresent()) {
+            log.error("Unable to get pipeconf of {} - BUG?");
+            return Optional.empty();
+        }
+        final PiPipeconf pipeconf = pipeconfService.getPipeconf(pipeconfId).get();
+        if (!pipeconf.extension(CPU_PORT_TXT).isPresent()) {
+            log.error("Missing {} extension from pipeconf {}",
+                      CPU_PORT_TXT, pipeconfId);
+            return Optional.empty();
+        }
+        return Optional.ofNullable(
+                readCpuPort(pipeconf.extension(CPU_PORT_TXT).get(),
+                            pipeconfId));
+    }
+
+    private Integer readCpuPort(InputStream stream, PiPipeconfId pipeconfId) {
+        try {
+            final BufferedReader buff = new BufferedReader(
+                    new InputStreamReader(stream));
+            final String str = buff.readLine();
+            buff.close();
+            if (str == null) {
+                log.error("Empty CPU port file for {}", pipeconfId);
+                return null;
+            }
+            try {
+                return Integer.parseInt(str);
+            } catch (NumberFormatException e) {
+                log.error("Invalid CPU port for {}: {}", pipeconfId, str);
+                return null;
+            }
+        } catch (IOException e) {
+            log.error("Unable to read CPU port file of {}: {}",
+                      pipeconfId, e.getMessage());
+            return null;
+        }
+    }
 }
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/IntProgrammableImpl.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/IntProgrammableImpl.java
index 01885bf..dec6332 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/IntProgrammableImpl.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/IntProgrammableImpl.java
@@ -15,29 +15,26 @@
  */
 package org.onosproject.pipelines.fabric;
 
-import com.google.common.collect.ImmutableBiMap;
 import com.google.common.collect.Sets;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
-import org.onlab.util.ImmutableByteSequence;
-import org.onlab.util.SharedExecutors;
+
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.inbandtelemetry.api.IntConfig;
 import org.onosproject.inbandtelemetry.api.IntIntent;
 import org.onosproject.inbandtelemetry.api.IntObjective;
 import org.onosproject.inbandtelemetry.api.IntProgrammable;
-import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
-import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TableId;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.Criterion;
@@ -45,32 +42,32 @@
 import org.onosproject.net.flow.criteria.PiCriterion;
 import org.onosproject.net.flow.criteria.TcpPortCriterion;
 import org.onosproject.net.flow.criteria.UdpPortCriterion;
-import org.onosproject.net.host.HostService;
-import org.onosproject.net.pi.model.PiActionId;
-import org.onosproject.net.pi.model.PiMatchFieldId;
 import org.onosproject.net.pi.model.PiTableId;
 import org.onosproject.net.pi.runtime.PiAction;
 import org.onosproject.net.pi.runtime.PiActionParam;
+import org.onosproject.provider.general.device.api.GeneralProviderDeviceConfig;
 import org.slf4j.Logger;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
+import static org.onlab.util.ImmutableByteSequence.copyFrom;
 import static org.slf4j.LoggerFactory.getLogger;
 
+/**
+ * Implementation of INT programmable behavior for fabric.p4. Currently supports
+ * only SOURCE and TRANSIT functionalities.
+ */
 public class IntProgrammableImpl extends AbstractHandlerBehaviour implements IntProgrammable {
+
+    private final Logger log = getLogger(getClass());
+
     // TODO: change this value to the value of diameter of a network.
+    private static final int DEFAULT_PRIORITY = 10000;
     private static final int MAXHOP = 64;
     private static final int PORTMASK = 0xffff;
-    private static final int IDLE_TIMEOUT = 100;
     private static final int PKT_INSTANCE_TYPE_INGRESS_CLONE = 1;
-    // Application name of the pipeline which adds this implementation to the pipeconf
-    private static final String PIPELINE_APP_NAME = "org.onosproject.pipelines.fabric";
-    private final Logger log = getLogger(getClass());
-    private ApplicationId appId;
 
     private static final Set<Criterion.Type> SUPPORTED_CRITERION = Sets.newHashSet(
             Criterion.Type.IPV4_DST, Criterion.Type.IPV4_SRC,
@@ -78,247 +75,225 @@
             Criterion.Type.TCP_SRC, Criterion.Type.TCP_DST,
             Criterion.Type.IP_PROTO);
 
+    private static final Set<PiTableId> TABLES_TO_CLEANUP = Sets.newHashSet(
+            FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_TB_INT_INSERT,
+            FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SOURCE,
+            FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SINK,
+            FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SOURCE_TB_INT_SOURCE,
+            FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_REPORT_TB_GENERATE_REPORT
+    );
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     private FlowRuleService flowRuleService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    private DeviceService deviceService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
-    private HostService hostService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY)
     private CoreService coreService;
-
+    private NetworkConfigService cfgService;
     private DeviceId deviceId;
-    private static final int DEFAULT_PRIORITY = 10000;
-    private static final ImmutableBiMap<Integer, PiActionId> INST_0003_ACTION_MAP =
-            ImmutableBiMap.<Integer, PiActionId>builder()
-                    .put(0, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I0)
-                    .put(1, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I1)
-                    .put(2, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I2)
-                    .put(3, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I3)
-                    .put(4, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I4)
-                    .put(5, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I5)
-                    .put(6, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I6)
-                    .put(7, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I7)
-                    .put(8, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I8)
-                    .put(9, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I9)
-                    .put(10, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I10)
-                    .put(11, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I11)
-                    .put(12, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I12)
-                    .put(13, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I13)
-                    .put(14, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I14)
-                    .put(15, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0003_I15)
-                    .build();
+    private ApplicationId appId;
 
-    private static final ImmutableBiMap<Integer, PiActionId> INST_0407_ACTION_MAP =
-            ImmutableBiMap.<Integer, PiActionId>builder()
-                    .put(0, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I0)
-                    .put(1, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I1)
-                    .put(2, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I2)
-                    .put(3, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I3)
-                    .put(4, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I4)
-                    .put(5, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I5)
-                    .put(6, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I6)
-                    .put(7, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I7)
-                    .put(8, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I8)
-                    .put(9, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I9)
-                    .put(10, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I10)
-                    .put(11, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I11)
-                    .put(12, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I12)
-                    .put(13, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I13)
-                    .put(14, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I14)
-                    .put(15, FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_SET_HEADER_0407_I15)
-                    .build();
-
-    @Override
-    public void init() {
+    private boolean setupBehaviour() {
         deviceId = this.data().deviceId();
         flowRuleService = handler().get(FlowRuleService.class);
-        deviceService = handler().get(DeviceService.class);
-        hostService = handler().get(HostService.class);
         coreService = handler().get(CoreService.class);
-        appId = coreService.getAppId(PIPELINE_APP_NAME);
+        cfgService = handler().get(NetworkConfigService.class);
+        appId = coreService.getAppId(PipeconfLoader.PIPELINE_APP_NAME);
         if (appId == null) {
-            log.warn("Application ID is null. Cannot initialize INT-pipeline.");
-            return;
+            log.warn("Application ID is null. Cannot initialize behaviour.");
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean init() {
+
+        if (!setupBehaviour()) {
+            return false;
         }
 
-        Set<PortNumber> hostPorts = deviceService.getPorts(deviceId).stream().filter(port ->
-                                         hostService.getConnectedHosts(
-                                                 new ConnectPoint(deviceId, port.number())).size() > 0
-        ).map(Port::number).collect(Collectors.toSet());
-        List<FlowRule> flowRules = new ArrayList<>();
+        final GeneralProviderDeviceConfig cfg = cfgService.getConfig(
+                deviceId, GeneralProviderDeviceConfig.class);
+        if (cfg == null) {
+            log.warn("Missing GeneralProviderDevice config for {}", deviceId);
+            return false;
+        }
+        final String switchId = cfg.protocolsInfo().containsKey("int") ?
+                cfg.protocolsInfo().get("int").configValues().get("switchId")
+                : null;
+        if (switchId == null || switchId.isEmpty()) {
+            log.warn("Missing INT device config for {}", deviceId);
+            return false;
+        }
 
-        // process_int_transit.tb_int_insert
-        PiActionParam transitIdParam = new PiActionParam(
-                FabricConstants.SWITCH_ID,
-                ImmutableByteSequence.copyFrom(
-                        Integer.parseInt(deviceId.toString().substring(
-                                deviceId.toString().length() - 2))));
+        PiActionParam transitIdParam;
+        try {
+            transitIdParam = new PiActionParam(
+                    FabricConstants.SWITCH_ID,
+                    // FIXME set switch ID from netcfg
+                    copyFrom(Integer.parseInt(switchId)));
+        } catch (NumberFormatException e) {
+            log.warn("Invalid INT switch ID for {}: {}", deviceId, switchId);
+            return false;
+        }
+
         PiAction transitAction = PiAction.builder()
-                .withId(FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_INT_TRANSIT)
+                .withId(FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_INIT_METADATA)
                 .withParameter(transitIdParam)
                 .build();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .piTableAction(transitAction)
                 .build();
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchPi(PiCriterion.builder().matchExact(
+                        FabricConstants.HDR_INT_HEADER_IS_VALID, (byte) 0x01)
+                                 .build())
+                .build();
 
         FlowRule transitFlowRule = DefaultFlowRule.builder()
+                .withSelector(selector)
                 .withTreatment(treatment)
                 .fromApp(appId)
                 .withPriority(DEFAULT_PRIORITY)
                 .makePermanent()
                 .forDevice(deviceId)
-                .forTable(FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INSERT)
+                .forTable(FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_TRANSIT_TB_INT_INSERT)
                 .build();
-        flowRules.add(transitFlowRule);
 
-        for (PortNumber portNumber: hostPorts) {
-            // process_set_source_sink.tb_set_source for each host-facing port
-            PiCriterion ingressCriterion = PiCriterion.builder()
-                    .matchExact(FabricConstants.STANDARD_METADATA_INGRESS_PORT, portNumber.toLong())
-                    .build();
-            TrafficSelector srcSelector = DefaultTrafficSelector.builder()
-                    .matchPi(ingressCriterion)
-                    .build();
-            PiAction setSourceAct = PiAction.builder()
-                    .withId(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_INT_SET_SOURCE)
-                    .build();
-            TrafficTreatment srcTreatment = DefaultTrafficTreatment.builder()
-                    .piTableAction(setSourceAct)
-                    .build();
-            FlowRule srcFlowRule = DefaultFlowRule.builder()
-                    .withSelector(srcSelector)
-                    .withTreatment(srcTreatment)
-                    .fromApp(appId)
-                    .withPriority(DEFAULT_PRIORITY)
-                    .makePermanent()
-                    .forDevice(deviceId)
-                    .forTable(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SOURCE)
-                    .build();
-            flowRules.add(srcFlowRule);
+        flowRuleService.applyFlowRules(transitFlowRule);
+        return true;
+    }
 
-            // process_set_source_sink.tb_set_sink
-            PiCriterion egressCriterion = PiCriterion.builder()
-                    .matchExact(FabricConstants.STANDARD_METADATA_EGRESS_PORT, portNumber.toLong())
-                    .build();
-            TrafficSelector sinkSelector = DefaultTrafficSelector.builder()
-                    .matchPi(egressCriterion)
-                    .build();
-            PiAction setSinkAct = PiAction.builder()
-                    .withId(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_INT_SET_SINK)
-                    .build();
-            TrafficTreatment sinkTreatment = DefaultTrafficTreatment.builder()
-                    .piTableAction(setSinkAct)
-                    .build();
-            FlowRule sinkFlowRule = DefaultFlowRule.builder()
-                    .withSelector(sinkSelector)
-                    .withTreatment(sinkTreatment)
-                    .fromApp(appId)
-                    .withPriority(DEFAULT_PRIORITY)
-                    .makePermanent()
-                    .forDevice(deviceId)
-                    .forTable(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SINK)
-                    .build();
-            flowRules.add(sinkFlowRule);
+    @Override
+    public boolean setSourcePort(PortNumber port) {
+
+        if (!setupBehaviour()) {
+            return false;
         }
-        flowRules.forEach(flowRule -> flowRuleService.applyFlowRules(flowRule));
 
-        // Populate tb_int_inst_0003 table
-        INST_0003_ACTION_MAP.forEach((matchValue, actionId) ->
-                 populateInstTableEntry(FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INST_0003,
-                                        FabricConstants.HDR_INT_HEADER_INSTRUCTION_MASK_0003,
-                                        matchValue,
-                                        actionId,
-                                        appId));
-        // Populate tb_int_inst_0407 table
-        INST_0407_ACTION_MAP.forEach((matchValue, actionId) ->
-                 populateInstTableEntry(FabricConstants.FABRIC_EGRESS_PROCESS_INT_TRANSIT_TB_INT_INST_0407,
-                                        FabricConstants.HDR_INT_HEADER_INSTRUCTION_MASK_0407,
-                                        matchValue,
-                                        actionId,
-                                        appId));
-    }
-
-    @Override
-    public CompletableFuture<Boolean> addIntObjective(IntObjective obj) {
-        // TODO: support different types of watchlist other than flow watchlist
-
-        return CompletableFuture.supplyAsync(
-                () -> processIntObjective(obj, true),
-                SharedExecutors.getPoolThreadExecutor()
-        );
-    }
-
-    @Override
-    public CompletableFuture<Boolean> removeIntObjective(IntObjective obj) {
-        return CompletableFuture.supplyAsync(
-                () -> processIntObjective(obj, false),
-                SharedExecutors.getPoolThreadExecutor()
-        );
-    }
-
-    @Override
-    public CompletableFuture<Boolean> setupIntConfig(IntConfig config) {
-        return CompletableFuture.supplyAsync(
-                () -> setupIntReportInternal(config),
-                SharedExecutors.getPoolThreadExecutor()
-        );
-    }
-
-    private void populateInstTableEntry(PiTableId tableId, PiMatchFieldId matchFieldId,
-                                        int matchValue, PiActionId actionId, ApplicationId appId) {
-        PiCriterion instCriterion = PiCriterion.builder()
-                .matchExact(matchFieldId, matchValue)
+        PiCriterion ingressCriterion = PiCriterion.builder()
+                .matchExact(FabricConstants.STANDARD_METADATA_INGRESS_PORT, port.toLong())
                 .build();
-        TrafficSelector instSelector = DefaultTrafficSelector.builder()
-                .matchPi(instCriterion)
+        TrafficSelector srcSelector = DefaultTrafficSelector.builder()
+                .matchPi(ingressCriterion)
                 .build();
-        PiAction instAction = PiAction.builder()
-                .withId(actionId)
+        PiAction setSourceAct = PiAction.builder()
+                .withId(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_INT_SET_SOURCE)
                 .build();
-        TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
-                .piTableAction(instAction)
+        TrafficTreatment srcTreatment = DefaultTrafficTreatment.builder()
+                .piTableAction(setSourceAct)
                 .build();
-
-        FlowRule instFlowRule = DefaultFlowRule.builder()
-                .withSelector(instSelector)
-                .withTreatment(instTreatment)
+        FlowRule srcFlowRule = DefaultFlowRule.builder()
+                .withSelector(srcSelector)
+                .withTreatment(srcTreatment)
+                .fromApp(appId)
                 .withPriority(DEFAULT_PRIORITY)
                 .makePermanent()
                 .forDevice(deviceId)
-                .forTable(tableId)
-                .fromApp(appId)
+                .forTable(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SOURCE)
                 .build();
+        flowRuleService.applyFlowRules(srcFlowRule);
+        return true;
+    }
 
-        flowRuleService.applyFlowRules(instFlowRule);
+    @Override
+    public boolean setSinkPort(PortNumber port) {
+
+        if (!setupBehaviour()) {
+            return false;
+        }
+
+        PiCriterion egressCriterion = PiCriterion.builder()
+                .matchExact(FabricConstants.STANDARD_METADATA_EGRESS_PORT, port.toLong())
+                .build();
+        TrafficSelector sinkSelector = DefaultTrafficSelector.builder()
+                .matchPi(egressCriterion)
+                .build();
+        PiAction setSinkAct = PiAction.builder()
+                .withId(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_INT_SET_SINK)
+                .build();
+        TrafficTreatment sinkTreatment = DefaultTrafficTreatment.builder()
+                .piTableAction(setSinkAct)
+                .build();
+        FlowRule sinkFlowRule = DefaultFlowRule.builder()
+                .withSelector(sinkSelector)
+                .withTreatment(sinkTreatment)
+                .fromApp(appId)
+                .withPriority(DEFAULT_PRIORITY)
+                .makePermanent()
+                .forDevice(deviceId)
+                .forTable(FabricConstants.FABRIC_INGRESS_PROCESS_SET_SOURCE_SINK_TB_SET_SINK)
+                .build();
+        flowRuleService.applyFlowRules(sinkFlowRule);
+        return true;
+    }
+
+    @Override
+    public boolean addIntObjective(IntObjective obj) {
+
+        if (!setupBehaviour()) {
+            return false;
+        }
+
+        return processIntObjective(obj, true);
+    }
+
+    @Override
+    public boolean removeIntObjective(IntObjective obj) {
+
+        if (!setupBehaviour()) {
+            return false;
+        }
+
+        return processIntObjective(obj, false);
+    }
+
+    @Override
+    public boolean setupIntConfig(IntConfig config) {
+
+        if (!setupBehaviour()) {
+            return false;
+        }
+
+        return setupIntReportInternal(config);
+    }
+
+    @Override
+    public void cleanup() {
+
+        if (!setupBehaviour()) {
+            return;
+        }
+
+        StreamSupport.stream(flowRuleService.getFlowEntries(
+                data().deviceId()).spliterator(), false)
+                .filter(f -> f.table().type() == TableId.Type.PIPELINE_INDEPENDENT)
+                .filter(f -> TABLES_TO_CLEANUP.contains((PiTableId) f.table()))
+                .forEach(flowRuleService::removeFlowRules);
+    }
+
+    @Override
+    public boolean supportsFunctionality(IntFunctionality functionality) {
+        // Sink not fully supported yet.
+        return functionality == IntFunctionality.SOURCE || functionality == IntFunctionality.TRANSIT;
     }
 
     private FlowRule buildWatchlistEntry(IntObjective obj) {
-        coreService = handler().get(CoreService.class);
-        appId = coreService.getAppId(PIPELINE_APP_NAME);
-        if (appId == null) {
-            log.warn("Application ID is null. Cannot initialize INT-pipeline.");
-            return null;
-        }
         int instructionBitmap = buildInstructionBitmap(obj.metadataTypes());
         PiActionParam maxHopParam = new PiActionParam(
                 FabricConstants.MAX_HOP,
-                ImmutableByteSequence.copyFrom(MAXHOP));
+                copyFrom(MAXHOP));
         PiActionParam instCntParam = new PiActionParam(
                 FabricConstants.INS_CNT,
-                ImmutableByteSequence.copyFrom(Integer.bitCount(instructionBitmap)));
+                copyFrom(Integer.bitCount(instructionBitmap)));
         PiActionParam inst0003Param = new PiActionParam(
                 FabricConstants.INS_MASK0003,
-                ImmutableByteSequence.copyFrom((instructionBitmap >> 12) & 0xF));
+                copyFrom((instructionBitmap >> 12) & 0xF));
         PiActionParam inst0407Param = new PiActionParam(
                 FabricConstants.INS_MASK0407,
-                ImmutableByteSequence.copyFrom((instructionBitmap >> 8) & 0xF));
+                copyFrom((instructionBitmap >> 8) & 0xF));
 
         PiAction intSourceAction = PiAction.builder()
-                .withId(FabricConstants.FABRIC_EGRESS_PROCESS_INT_SOURCE_INT_SOURCE_DSCP)
+                .withId(FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SOURCE_INT_SOURCE_DSCP)
                 .withParameter(maxHopParam)
                 .withParameter(instCntParam)
                 .withParameter(inst0003Param)
@@ -372,13 +347,13 @@
         }
 
         return DefaultFlowRule.builder()
-                .forDevice(this.data().deviceId())
+                .forDevice(deviceId)
                 .withSelector(sBuilder.build())
                 .withTreatment(instTreatment)
                 .withPriority(DEFAULT_PRIORITY)
-                .forTable(FabricConstants.FABRIC_EGRESS_PROCESS_INT_SOURCE_TB_INT_SOURCE)
+                .forTable(FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_SOURCE_TB_INT_SOURCE)
                 .fromApp(appId)
-                .withIdleTimeout(IDLE_TIMEOUT)
+                .makePermanent()
                 .build();
     }
 
@@ -419,12 +394,12 @@
     }
 
     /**
-     * Returns a subset of Criterion from given selector,
-     * which is unsupported by this INT pipeline.
+     * Returns a subset of Criterion from given selector, which is unsupported
+     * by this INT pipeline.
      *
      * @param selector a traffic selector
-     * @return a subset of Criterion from given selector, unsupported by this INT pipeline,
-     *  empty if all criteria are supported.
+     * @return a subset of Criterion from given selector, unsupported by this
+     * INT pipeline, empty if all criteria are supported.
      */
     private Set<Criterion> unsupportedSelectors(TrafficSelector selector) {
         return selector.criteria().stream()
@@ -433,11 +408,9 @@
     }
 
     private boolean processIntObjective(IntObjective obj, boolean install) {
-        flowRuleService = handler().get(FlowRuleService.class);
-        deviceId = this.data().deviceId();
         if (install && !unsupportedSelectors(obj.selector()).isEmpty()) {
-            log.warn("Device {} does not support criteria {} for INT.",
-                     deviceId, unsupportedSelectors(obj.selector()));
+            log.warn("Criteria {} not supported by {} for INT watchlist",
+                     unsupportedSelectors(obj.selector()), deviceId);
             return false;
         }
 
@@ -459,44 +432,42 @@
     }
 
     private boolean setupIntReportInternal(IntConfig cfg) {
-        flowRuleService = handler().get(FlowRuleService.class);
-
-        FlowRule reportRule = buildReportEntry(cfg, PKT_INSTANCE_TYPE_INGRESS_CLONE);
-        if (reportRule != null) {
-            flowRuleService.applyFlowRules(reportRule);
-            log.info("Report entry {} has been added to {}", reportRule, this.data().deviceId());
-            return true;
-        } else {
-            log.warn("Failed to add report entry on {}", this.data().deviceId());
-            return false;
-        }
+        // Report not fully supported yet.
+        return true;
+        // FlowRule reportRule = buildReportEntry(cfg, PKT_INSTANCE_TYPE_INGRESS_CLONE);
+        // if (reportRule != null) {
+        //     flowRuleService.applyFlowRules(reportRule);
+        //     log.info("Report entry {} has been added to {}", reportRule, this.data().deviceId());
+        //     return true;
+        // } else {
+        //     log.warn("Failed to add report entry on {}", this.data().deviceId());
+        //     return false;
+        // }
     }
 
     private FlowRule buildReportEntry(IntConfig cfg, int type) {
-        coreService = handler().get(CoreService.class);
-        appId = coreService.getAppId(PIPELINE_APP_NAME);
-        if (appId == null) {
-            log.warn("Application ID is null. Cannot build report entry.");
+
+        if (!setupBehaviour()) {
             return null;
         }
 
         PiActionParam srcMacParam = new PiActionParam(
                 FabricConstants.SRC_MAC,
-                ImmutableByteSequence.copyFrom(cfg.sinkMac().toBytes()));
+                copyFrom(cfg.sinkMac().toBytes()));
         PiActionParam nextHopMacParam = new PiActionParam(
                 FabricConstants.MON_MAC,
-                ImmutableByteSequence.copyFrom(cfg.collectorNextHopMac().toBytes()));
+                copyFrom(cfg.collectorNextHopMac().toBytes()));
         PiActionParam srcIpParam = new PiActionParam(
                 FabricConstants.SRC_IP,
-                ImmutableByteSequence.copyFrom(cfg.sinkIp().toOctets()));
+                copyFrom(cfg.sinkIp().toOctets()));
         PiActionParam monIpParam = new PiActionParam(
                 FabricConstants.MON_IP,
-                ImmutableByteSequence.copyFrom(cfg.collectorIp().toOctets()));
+                copyFrom(cfg.collectorIp().toOctets()));
         PiActionParam monPortParam = new PiActionParam(
                 FabricConstants.MON_PORT,
-                ImmutableByteSequence.copyFrom(cfg.collectorPort().toInt()));
+                copyFrom(cfg.collectorPort().toInt()));
         PiAction reportAction = PiAction.builder()
-                .withId(FabricConstants.FABRIC_EGRESS_PROCESS_INT_REPORT_DO_REPORT_ENCAPSULATION)
+                .withId(FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_REPORT_DO_REPORT_ENCAPSULATION)
                 .withParameter(srcMacParam)
                 .withParameter(nextHopMacParam)
                 .withParameter(srcIpParam)
@@ -513,7 +484,7 @@
                 .withPriority(DEFAULT_PRIORITY)
                 .makePermanent()
                 .forDevice(this.data().deviceId())
-                .forTable(FabricConstants.FABRIC_EGRESS_PROCESS_INT_REPORT_TB_GENERATE_REPORT)
+                .forTable(FabricConstants.FABRIC_EGRESS_PROCESS_INT_MAIN_PROCESS_INT_REPORT_TB_GENERATE_REPORT)
                 .build();
     }
 
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
index 9dd385e..48ec2ab 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/PipeconfLoader.java
@@ -23,7 +23,6 @@
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.onosproject.core.CoreService;
 import org.onosproject.inbandtelemetry.api.IntProgrammable;
-import org.onosproject.net.PortNumber;
 import org.onosproject.net.behaviour.Pipeliner;
 import org.onosproject.net.device.PortStatisticsDiscovery;
 import org.onosproject.net.pi.model.DefaultPiPipeconf;
@@ -44,7 +43,6 @@
 import java.net.URL;
 import java.util.Collection;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
 import static java.lang.String.format;
@@ -64,12 +62,11 @@
 
     private static Logger log = getLogger(PipeconfLoader.class);
 
+    static final String PIPELINE_APP_NAME = "org.onosproject.pipelines.fabric";
+
     private static final String BASE_PIPECONF_ID = "org.onosproject.pipelines";
-
     private static final String P4C_OUT_PATH = "/p4c-out";
 
-    private static final String PIPELINE_APP_NAME = "org.onosproject.pipelines.fabric";
-
     // profile/target/platform
     private static final String P4C_RES_BASE_PATH = P4C_OUT_PATH + "/%s/%s/%s/";
 
@@ -79,13 +76,12 @@
     private static final String DEFAULT_PLATFORM = "default";
     private static final String BMV2_JSON = "bmv2.json";
     private static final String P4INFO_TXT = "p4info.txt";
+    private static final String CPU_PORT_TXT = "cpu_port.txt";
     private static final String TOFINO_BIN = "tofino.bin";
     private static final String TOFINO_CTX_JSON = "context.json";
     private static final String INT_PROFILE_SUFFIX = "-int";
     private static final String FULL_PROFILE_SUFFIX = "-full";
 
-    private static final int BMV2_CPU_PORT = 255;
-
     private static final Collection<PiPipeconf> PIPECONFS = buildAllPipeconf();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
@@ -131,45 +127,58 @@
         String profile = pieces[1];
         String target = pieces[2];
         String platform = pieces[3];
+        final DefaultPiPipeconf.Builder pipeconfBuilder;
         try {
             switch (target) {
                 case BMV2:
-                    return buildBmv2Pipeconf(profile, platform);
+                    pipeconfBuilder = bmv2Pipeconf(profile, platform);
+                    break;
                 case TOFINO:
-                    return buildTofinoPipeconf(profile, platform);
+                    pipeconfBuilder = tofinoPipeconf(profile, platform);
+                    break;
                 default:
                     log.warn("Unknown target '{}', skipping pipeconf build...",
                              target);
                     return null;
             }
         } catch (FileNotFoundException e) {
-            log.warn("Unable to build pipeconf at {} because one or more p4c outputs are missing",
-                     path);
+            log.warn("Unable to build pipeconf at {} because file is missing: {}",
+                     path, e.getMessage());
             return null;
         }
+        // Add IntProgrammable behaviour for INT-enabled profiles.
+        if (profile.endsWith(INT_PROFILE_SUFFIX) || profile.endsWith(FULL_PROFILE_SUFFIX)) {
+            pipeconfBuilder.addBehaviour(IntProgrammable.class, IntProgrammableImpl.class);
+        }
+        return pipeconfBuilder.build();
     }
 
-    private static PiPipeconf buildBmv2Pipeconf(String profile, String platform)
+    private static DefaultPiPipeconf.Builder bmv2Pipeconf(
+            String profile, String platform)
             throws FileNotFoundException {
         final URL bmv2JsonUrl = PipeconfLoader.class.getResource(format(
                 P4C_RES_BASE_PATH + BMV2_JSON, profile, BMV2, platform));
         final URL p4InfoUrl = PipeconfLoader.class.getResource(format(
                 P4C_RES_BASE_PATH + P4INFO_TXT, profile, BMV2, platform));
-        if (bmv2JsonUrl == null || p4InfoUrl == null) {
-            throw new FileNotFoundException();
+        final URL cpuPortUrl = PipeconfLoader.class.getResource(format(
+                P4C_RES_BASE_PATH + CPU_PORT_TXT, profile, BMV2, platform));
+        if (bmv2JsonUrl == null) {
+            throw new FileNotFoundException(BMV2_JSON);
         }
-
-        DefaultPiPipeconf.Builder builder = basePipeconfBuilder(
-                profile, platform, p4InfoUrl, Bmv2FabricInterpreter.class)
+        if (p4InfoUrl == null) {
+            throw new FileNotFoundException(P4INFO_TXT);
+        }
+        if (cpuPortUrl == null) {
+            throw new FileNotFoundException(CPU_PORT_TXT);
+        }
+        return basePipeconfBuilder(profile, platform, p4InfoUrl, cpuPortUrl)
+                .addBehaviour(PortStatisticsDiscovery.class,
+                              FabricPortStatisticsDiscovery.class)
                 .addExtension(ExtensionType.BMV2_JSON, bmv2JsonUrl);
-        // Add IntProgrammable behaviour for INT-enabled profiles.
-        if (profile.endsWith(INT_PROFILE_SUFFIX) || profile.endsWith(FULL_PROFILE_SUFFIX)) {
-            builder.addBehaviour(IntProgrammable.class, IntProgrammableImpl.class);
-        }
-        return builder.build();
     }
 
-    private static PiPipeconf buildTofinoPipeconf(String profile, String platform)
+    private static DefaultPiPipeconf.Builder tofinoPipeconf(
+            String profile, String platform)
             throws FileNotFoundException {
         final URL tofinoBinUrl = PipeconfLoader.class.getResource(format(
                 P4C_RES_BASE_PATH + TOFINO_BIN, profile, TOFINO, platform));
@@ -177,19 +186,27 @@
                 P4C_RES_BASE_PATH + TOFINO_CTX_JSON, profile, TOFINO, platform));
         final URL p4InfoUrl = PipeconfLoader.class.getResource(format(
                 P4C_RES_BASE_PATH + P4INFO_TXT, profile, TOFINO, platform));
-        if (tofinoBinUrl == null || contextJsonUrl == null || p4InfoUrl == null) {
-            throw new FileNotFoundException();
+        final URL cpuPortUrl = PipeconfLoader.class.getResource(format(
+                P4C_RES_BASE_PATH + CPU_PORT_TXT, profile, TOFINO, platform));
+        if (tofinoBinUrl == null) {
+            throw new FileNotFoundException(TOFINO_BIN);
         }
-        return basePipeconfBuilder(
-                profile, platform, p4InfoUrl, FabricInterpreter.class)
+        if (contextJsonUrl == null) {
+            throw new FileNotFoundException(TOFINO_CTX_JSON);
+        }
+        if (p4InfoUrl == null) {
+            throw new FileNotFoundException(P4INFO_TXT);
+        }
+        if (cpuPortUrl == null) {
+            throw new FileNotFoundException(CPU_PORT_TXT);
+        }
+        return basePipeconfBuilder(profile, platform, p4InfoUrl, cpuPortUrl)
                 .addExtension(ExtensionType.TOFINO_BIN, tofinoBinUrl)
-                .addExtension(ExtensionType.TOFINO_CONTEXT_JSON, contextJsonUrl)
-                .build();
+                .addExtension(ExtensionType.TOFINO_CONTEXT_JSON, contextJsonUrl);
     }
 
     private static DefaultPiPipeconf.Builder basePipeconfBuilder(
-            String profile, String platform, URL p4InfoUrl,
-            Class<? extends FabricInterpreter> interpreterClass) {
+            String profile, String platform, URL p4InfoUrl, URL cpuPortUrl) {
         final String pipeconfId = platform.equals(DEFAULT_PLATFORM)
                 // Omit platform if default, e.g. with BMv2 pipeconf
                 ? format("%s.%s", BASE_PIPECONF_ID, profile)
@@ -199,12 +216,11 @@
                 .withId(new PiPipeconfId(pipeconfId))
                 .withPipelineModel(model)
                 .addBehaviour(PiPipelineInterpreter.class,
-                              interpreterClass)
+                              FabricInterpreter.class)
                 .addBehaviour(Pipeliner.class,
                               FabricPipeliner.class)
-                .addBehaviour(PortStatisticsDiscovery.class,
-                              FabricPortStatisticsDiscovery.class)
-                .addExtension(ExtensionType.P4_INFO_TEXT, p4InfoUrl);
+                .addExtension(ExtensionType.P4_INFO_TEXT, p4InfoUrl)
+                .addExtension(ExtensionType.CPU_PORT_TXT, cpuPortUrl);
     }
 
     private static PiPipelineModel parseP4Info(URL p4InfoUrl) {
@@ -214,16 +230,4 @@
             throw new IllegalStateException(e);
         }
     }
-
-    // TODO: define interpreters with logical port mapping for Tofino platforms.
-    public static class Bmv2FabricInterpreter extends FabricInterpreter {
-        @Override
-        public Optional<Integer> mapLogicalPortNumber(PortNumber port) {
-            if (port.equals(PortNumber.CONTROLLER)) {
-                return Optional.of(BMV2_CPU_PORT);
-            } else {
-                return Optional.empty();
-            }
-        }
-    }
 }