VLAN support on host(af-packet) interface.

On host interface if a VLAN tagged packet is received, linux kernel removes
the VLAN header from packet byte stream and adds metadata in tpacket2_hdr.
This patch explicitely checks for the presense of VLAN metadata and adds it
in VPP packet.

Change-Id: I0ba35c1e98dbc008ce18d032f22f2717d610c1aa
Signed-off-by: Akshaya N <akshaya@rtbrick.com>
diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c
index d3af41b..99c91f3 100644
--- a/src/vnet/devices/af_packet/node.c
+++ b/src/vnet/devices/af_packet/node.c
@@ -173,12 +173,35 @@
 	      /* copy data */
 	      u32 bytes_to_copy =
 		data_len > n_buffer_bytes ? n_buffer_bytes : data_len;
+	      u32 vlan_len = 0;
+	      u32 bytes_copied = 0;
 	      b0->current_data = 0;
-	      clib_memcpy (vlib_buffer_get_current (b0),
-			   (u8 *) tph + tph->tp_mac + offset, bytes_to_copy);
+	      /* Kernel removes VLAN headers, so reconstruct VLAN */
+	      if (PREDICT_FALSE (tph->tp_status & TP_STATUS_VLAN_VALID))
+		{
+		  if (PREDICT_TRUE (offset == 0))
+		    {
+		      clib_memcpy (vlib_buffer_get_current (b0),
+				   (u8 *) tph + tph->tp_mac,
+				   sizeof (ethernet_header_t));
+		      ethernet_header_t *eth = vlib_buffer_get_current (b0);
+		      ethernet_vlan_header_t *vlan =
+			(ethernet_vlan_header_t *) (eth + 1);
+		      vlan->priority_cfi_and_id =
+			clib_host_to_net_u16 (tph->tp_vlan_tci);
+		      vlan->type = eth->type;
+		      eth->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
+		      vlan_len = sizeof (ethernet_vlan_header_t);
+		      bytes_copied = sizeof (ethernet_header_t);
+		    }
+		}
+	      clib_memcpy (((u8 *) vlib_buffer_get_current (b0)) +
+			   bytes_copied + vlan_len,
+			   (u8 *) tph + tph->tp_mac + offset + bytes_copied,
+			   (bytes_to_copy - bytes_copied));
 
 	      /* fill buffer header */
-	      b0->current_length = bytes_to_copy;
+	      b0->current_length = bytes_to_copy + vlan_len;
 
 	      if (offset == 0)
 		{