pg: add trace information for pg tx node

Change-Id: I31730d58c34331f25f5b02cd065be94251f1302c
Signed-off-by: Damjan Marion <damarion@cisco.com>
diff --git a/src/vnet/pg/output.c b/src/vnet/pg/output.c
index 3d1f266..ab57dee 100644
--- a/src/vnet/pg/output.c
+++ b/src/vnet/pg/output.c
@@ -37,6 +37,7 @@
  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <vppinfra/string.h>
 #include <vlib/vlib.h>
 #include <vnet/vnet.h>
 #include <vnet/pg/pg.h>
@@ -56,19 +57,28 @@
     while (__sync_lock_test_and_set (pif->lockp, 1))
       ;
 
-  if (pif->pcap_file_name != 0)
+  while (n_left > 0)
     {
-      while (n_left > 0)
-	{
-	  n_left--;
-	  u32 bi0 = buffers[0];
-	  buffers++;
+      n_left--;
+      u32 bi0 = buffers[0];
+      vlib_buffer_t *b = vlib_get_buffer (vm, bi0);
+      buffers++;
 
-	  pcap_add_buffer (&pif->pcap_main, vm, bi0,
-			   ETHERNET_MAX_PACKET_BYTES);
+      if (b->flags & VLIB_BUFFER_IS_TRACED)
+	{
+	  pg_output_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
+	  t->buffer_index = bi0;
+	  clib_memcpy (&t->buffer, b, sizeof (b[0]) - sizeof (b->pre_data));
+	  clib_memcpy (t->buffer.pre_data, b->data + b->current_data,
+		       sizeof (t->buffer.pre_data));
 	}
-      pcap_write (&pif->pcap_main);
+
+      if (pif->pcap_file_name != 0)
+	pcap_add_buffer (&pif->pcap_main, vm, bi0, ETHERNET_MAX_PACKET_BYTES);
     }
+  if (pif->pcap_file_name != 0)
+    pcap_write (&pif->pcap_main);
+
 
   vlib_buffer_free (vm, vlib_frame_args (frame), n_buffers);
   if (PREDICT_FALSE (pif->lockp != 0))
diff --git a/src/vnet/pg/pg.h b/src/vnet/pg/pg.h
index a402783..111df91 100644
--- a/src/vnet/pg/pg.h
+++ b/src/vnet/pg/pg.h
@@ -372,6 +372,13 @@
 
 clib_error_t *pg_capture (pg_capture_args_t * a);
 
+typedef struct
+{
+  vlib_buffer_t buffer;
+  u32 buffer_index;
+}
+pg_output_trace_t;
+
 #endif /* included_vlib_pg_h */
 
 /*
diff --git a/src/vnet/pg/stream.c b/src/vnet/pg/stream.c
index 1ed7189..c46875e 100644
--- a/src/vnet/pg/stream.c
+++ b/src/vnet/pg/stream.c
@@ -95,6 +95,25 @@
 }
 
 static u8 *
+format_pg_output_trace (u8 * s, va_list * va)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
+  pg_output_trace_t *t = va_arg (*va, pg_output_trace_t *);
+  uword indent = format_get_indent (s);
+
+  s = format (s, "%Ubuffer 0x%x: %U",
+	      format_white_space, indent,
+	      t->buffer_index, format_vlib_buffer, &t->buffer);
+
+  s = format (s, "\n%U%U", format_white_space, indent,
+	      format_ethernet_header_with_length, t->buffer.pre_data,
+	      sizeof (t->buffer.pre_data));
+
+  return s;
+}
+
+static u8 *
 format_pg_interface_name (u8 * s, va_list * args)
 {
   pg_main_t *pg = &pg_main;
@@ -125,6 +144,7 @@
   .name = "pg",
   .tx_function = pg_output,
   .format_device_name = format_pg_interface_name,
+  .format_tx_trace = format_pg_output_trace,
   .admin_up_down_function = pg_interface_admin_up_down,
 };
 /* *INDENT-ON* */