Improvement in fabric.p4 and bng.p4

- fabric.p4 now supports double tagged hosts
- bng.p4 now only manages PPPoE termination
- bng_ingress moved at the end of the fabric pipeline

Change-Id: Iff62238fde9ec6ddf7311312a98c041e3ab3aa8d
diff --git a/pipelines/fabric/src/main/resources/include/parser.p4 b/pipelines/fabric/src/main/resources/include/parser.p4
index e234676..2d6a1d4 100644
--- a/pipelines/fabric/src/main/resources/include/parser.p4
+++ b/pipelines/fabric/src/main/resources/include/parser.p4
@@ -40,14 +40,14 @@
 
     state parse_ethernet {
         packet.extract(hdr.ethernet);
-        fabric_metadata.eth_type = hdr.ethernet.eth_type;
+        fabric_metadata.last_eth_type = hdr.ethernet.eth_type;
         fabric_metadata.vlan_id = DEFAULT_VLAN_ID;
         transition select(hdr.ethernet.eth_type){
             ETHERTYPE_VLAN: parse_vlan_tag;
             ETHERTYPE_MPLS: parse_mpls;
-            ETHERTYPE_IPV4: parse_ipv4;
+            ETHERTYPE_IPV4: pre_parse_ipv4;
 #ifdef WITH_IPV6
-            ETHERTYPE_IPV6: parse_ipv6;
+            ETHERTYPE_IPV6: pre_parse_ipv6;
 #endif // WITH_IPV6
             default: accept;
         }
@@ -56,25 +56,27 @@
     state parse_vlan_tag {
         packet.extract(hdr.vlan_tag);
         transition select(hdr.vlan_tag.eth_type){
-            ETHERTYPE_IPV4: parse_ipv4;
+            ETHERTYPE_IPV4: pre_parse_ipv4;
 #ifdef WITH_IPV6
-            ETHERTYPE_IPV6: parse_ipv6;
+            ETHERTYPE_IPV6: pre_parse_ipv6;
 #endif // WITH_IPV6
             ETHERTYPE_MPLS: parse_mpls;
-#if defined(WITH_XCONNECT) || defined(WITH_BNG)
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
             ETHERTYPE_VLAN: parse_inner_vlan_tag;
+            ETHERTYPE_QINQ: parse_inner_vlan_tag;
+            ETHERTYPE_QINQ_NON_STD: parse_inner_vlan_tag;
 #endif // WITH_XCONNECT
             default: accept;
         }
     }
 
-#if defined(WITH_XCONNECT) || defined(WITH_BNG)
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
     state parse_inner_vlan_tag {
         packet.extract(hdr.inner_vlan_tag);
         transition select(hdr.inner_vlan_tag.eth_type){
-            ETHERTYPE_IPV4: parse_ipv4;
+            ETHERTYPE_IPV4: pre_parse_ipv4;
 #ifdef WITH_IPV6
-            ETHERTYPE_IPV6: parse_ipv6;
+            ETHERTYPE_IPV6: pre_parse_ipv6;
 #endif // WITH_IPV6
             ETHERTYPE_MPLS: parse_mpls;
 #ifdef WITH_BNG
@@ -84,16 +86,16 @@
             default: accept;
         }
     }
-#endif // WITH_XCONNECT
+#endif // WITH_XCONNECT || WITH_BNG || WITH_DOUBLE_VLAN_TERMINATION
 
 #ifdef WITH_BNG
     state parse_pppoe {
         packet.extract(hdr.pppoe);
         transition select(hdr.pppoe.protocol) {
             PPPOE_PROTOCOL_MPLS: parse_mpls;
-            PPPOE_PROTOCOL_IP4: parse_ipv4;
+            PPPOE_PROTOCOL_IP4: pre_parse_ipv4;
 #ifdef WITH_IPV6
-            PPPOE_PROTOCOL_IP6: parse_ipv6;
+            PPPOE_PROTOCOL_IP6: pre_parse_ipv6;
 #endif // WITH_IPV6
             default: accept;
         }
@@ -102,13 +104,16 @@
 
     state parse_mpls {
         packet.extract(hdr.mpls);
+        fabric_metadata.is_mpls = _TRUE;
         fabric_metadata.mpls_label = hdr.mpls.label;
         fabric_metadata.mpls_ttl = hdr.mpls.ttl;
         // There is only one MPLS label for this fabric.
         // Assume header after MPLS header is IPv4/IPv6
         // Lookup first 4 bits for version
         transition select(packet.lookahead<bit<IP_VER_LENGTH>>()) {
-            //The packet should be either IPv4 or IPv6.
+            // The packet should be either IPv4 or IPv6.
+            // If we have MPLS, go directly to parsing state without
+            // moving to pre_ states, the packet is considered MPLS
             IP_VERSION_4: parse_ipv4;
 #ifdef WITH_IPV6
             IP_VERSION_6: parse_ipv6;
@@ -117,6 +122,11 @@
         }
     }
 
+    // Intermediate state to set is_ipv4
+    state pre_parse_ipv4 {
+        fabric_metadata.is_ipv4 = _TRUE;
+        transition parse_ipv4;
+    }
     state parse_ipv4 {
         packet.extract(hdr.ipv4);
         fabric_metadata.ip_proto = hdr.ipv4.protocol;
@@ -132,6 +142,11 @@
     }
 
 #ifdef WITH_IPV6
+    // Intermediate state to set is_ipv6
+    state pre_parse_ipv6 {
+        fabric_metadata.is_ipv6 = _TRUE;
+        transition parse_ipv6;
+    }
     state parse_ipv6 {
         packet.extract(hdr.ipv6);
         fabric_metadata.ip_proto = hdr.ipv6.next_hdr;
@@ -270,9 +285,9 @@
 #endif // WITH_INT_SINK
         packet.emit(hdr.ethernet);
         packet.emit(hdr.vlan_tag);
-#if defined(WITH_XCONNECT) || defined(WITH_BNG)
+#if defined(WITH_XCONNECT) || defined(WITH_BNG) || defined(WITH_DOUBLE_VLAN_TERMINATION)
         packet.emit(hdr.inner_vlan_tag);
-#endif // WITH_XCONNECT
+#endif // WITH_XCONNECT || WITH_BNG || WITH_DOUBLE_VLAN_TERMINATION
 #ifdef WITH_BNG
         packet.emit(hdr.pppoe);
 #endif // WITH_BNG