Improve fabric.p4 with BNG support

Change-Id: I08f8991d8cf432785e0c409354b6301c8983bfb4
diff --git a/pipelines/fabric/src/main/resources/include/bng.p4 b/pipelines/fabric/src/main/resources/include/bng.p4
index 9e56fe4..11e4639 100644
--- a/pipelines/fabric/src/main/resources/include/bng.p4
+++ b/pipelines/fabric/src/main/resources/include/bng.p4
@@ -44,6 +44,7 @@
     vlan_id_t s_tag = hdr.vlan_tag.vlan_id;
     vlan_id_t c_tag = hdr.inner_vlan_tag.vlan_id;
 
+    _BOOL drop = _FALSE;
     // TABLE: t_line_map
     // Maps double VLAN tags to line ID. Line IDs are used to uniquelly identify
     // a subscriber.
@@ -107,7 +108,7 @@
         fmeta.skip_forwarding = _TRUE;
         fmeta.skip_next = _TRUE;
         mark_to_drop(smeta);
-        c_dropped.count(fmeta.bng.line_id);
+        drop = _TRUE;
     }
 
     action term_enabled_v4() {
@@ -158,10 +159,16 @@
 
         if (hdr.ipv4.isValid()) {
             t_pppoe_term_v4.apply();
+            if (drop == _TRUE) {
+                c_dropped.count(fmeta.bng.line_id);
+            }
         }
 #ifdef WITH_IPV6
         else if (hdr.ipv6.isValid()) {
             t_pppoe_term_v6.apply();
+            if (drop == _TRUE) {
+                c_dropped.count(fmeta.bng.line_id);
+             }
         }
 #endif // WITH_IPV6
     }
@@ -180,6 +187,7 @@
     // Downstream line map tables.
     // Map IP dest address to line ID and next ID. Setting a next ID here
     // allows to skip the fabric.p4 forwarding stage later.
+    _BOOL prio = _FALSE;
 
     @hidden
     action set_line(bit<32> line_id) {
@@ -234,13 +242,11 @@
     // everything is tagged and metered as best-effort traffic.
 
     action qos_prio() {
-        m_prio.execute_meter((bit<32>)fmeta.bng.line_id,
-                             fmeta.bng.ds_meter_result);
+        prio = _TRUE;
     }
 
     action qos_besteff() {
-        m_besteff.execute_meter((bit<32>)fmeta.bng.line_id,
-                                fmeta.bng.ds_meter_result);
+        // no-op
     }
 
     table t_qos_v4 {
@@ -283,6 +289,13 @@
                 // destined to subscribers, e.g. to services in the compute
                 // nodes.
                 t_qos_v4.apply();
+                if (prio == _TRUE) {
+                    m_prio.execute_meter((bit<32>)fmeta.bng.line_id,
+                                          fmeta.bng.ds_meter_result);
+                } else {
+                    m_besteff.execute_meter((bit<32>)fmeta.bng.line_id,
+                                            fmeta.bng.ds_meter_result);
+                }
             }
         }
 #ifdef WITH_IPV6
@@ -290,6 +303,13 @@
         else if (hdr.ipv6.isValid()) {
             if (t_line_map_v6.apply().hit) {
                 t_qos_v6.apply();
+                if (prio == _TRUE) {
+                    m_prio.execute_meter((bit<32>)fmeta.bng.line_id,
+                                          fmeta.bng.ds_meter_result);
+                } else {
+                    m_besteff.execute_meter((bit<32>)fmeta.bng.line_id,
+                                            fmeta.bng.ds_meter_result);
+                }
             }
         }
 #endif // WITH_IPV6
diff --git a/pipelines/fabric/src/main/resources/include/define.p4 b/pipelines/fabric/src/main/resources/include/define.p4
index 8f70fb4..8058416 100644
--- a/pipelines/fabric/src/main/resources/include/define.p4
+++ b/pipelines/fabric/src/main/resources/include/define.p4
@@ -115,6 +115,7 @@
 
 const bit<16> PPPOE_PROTOCOL_IP4 = 0x0021;
 const bit<16> PPPOE_PROTOCOL_IP6 = 0x0057;
+const bit<16> PPPOE_PROTOCOL_MPLS = 0x0281;
 
 const bit<8> PROTO_ICMP = 1;
 const bit<8> PROTO_TCP = 6;
diff --git a/pipelines/fabric/src/main/resources/include/parser.p4 b/pipelines/fabric/src/main/resources/include/parser.p4
index e0f9fc5..e234676 100644
--- a/pipelines/fabric/src/main/resources/include/parser.p4
+++ b/pipelines/fabric/src/main/resources/include/parser.p4
@@ -90,6 +90,7 @@
     state parse_pppoe {
         packet.extract(hdr.pppoe);
         transition select(hdr.pppoe.protocol) {
+            PPPOE_PROTOCOL_MPLS: parse_mpls;
             PPPOE_PROTOCOL_IP4: parse_ipv4;
 #ifdef WITH_IPV6
             PPPOE_PROTOCOL_IP6: parse_ipv6;