Add buffer tracing to the dispatch tracer

Change-Id: I56f25d653b71a25c70e6c5c1a93dd9c5158f2079
Signed-off-by: Dave Barach <dave@barachs.net>
diff --git a/src/vlib/main.c b/src/vlib/main.c
index 77dc573..d1babdb 100644
--- a/src/vlib/main.c
+++ b/src/vlib/main.c
@@ -953,12 +953,16 @@
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **bufp, *b;
   u8 name_tlv[64];
   pcap_main_t *pm = &vm->dispatch_pcap_main;
+  vlib_trace_main_t *tm = &vm->trace_main;
   u32 capture_size;
   vlib_node_t *n;
+  u8 *packet_trace = 0;
   i32 n_left;
   f64 time_now = vlib_time_now (vm);
   u32 *from;
   u32 name_length;
+  u16 trace_length;
+  u8 version[2];
   u8 *d;
 
   /* Input nodes don't have frames yet */
@@ -985,13 +989,38 @@
 	{
 	  b = bufp[i];
 
+	  version[0] = VLIB_PCAP_MAJOR_VERSION;
+	  version[1] = VLIB_PCAP_MINOR_VERSION;
+
+	  vec_reset_length (packet_trace);
+
+	  /* Is this packet traced? */
+	  if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
+	    {
+	      vlib_trace_header_t **h
+		= pool_elt_at_index (tm->trace_buffer_pool, b->trace_index);
+
+	      packet_trace = format (packet_trace, "%U%c",
+				     format_vlib_trace, vm, h[0], 0);
+	    }
+
 	  /* Figure out how many bytes we're capturing */
-	  capture_size = (sizeof (vlib_buffer_t) - VLIB_BUFFER_PRE_DATA_SIZE) + vlib_buffer_length_in_chain (vm, b) + sizeof (u32) + +(name_length + 2);	/* +2: count plus NULL byte */
+          /* *INDENT-OFF* */
+	  capture_size = (sizeof (vlib_buffer_t) - VLIB_BUFFER_PRE_DATA_SIZE)
+            + sizeof (version)
+            + vlib_buffer_length_in_chain (vm, b)
+            + sizeof (u32) + (name_length + 2)	/* +2: count plus NULL byte */
+	    + (vec_len (packet_trace) + 2);	/* +2: trace count */
+          /* *INDENT-ON* */
 
 	  clib_spinlock_lock_if_init (&pm->lock);
-	  n_left = clib_min (capture_size, 512);
+	  n_left = clib_min (capture_size, 16384);
 	  d = pcap_add_packet (pm, time_now, n_left, capture_size);
 
+	  /* Copy the (major, minor) version numbers */
+	  clib_memcpy_fast (d, version, sizeof (version));
+	  d += sizeof (version);
+
 	  /* Copy the buffer index */
 	  clib_memcpy_fast (d, &from[i], sizeof (u32));
 	  d += 4;
@@ -1004,8 +1033,22 @@
 	  clib_memcpy_fast (d, b, sizeof (*b) - VLIB_BUFFER_PRE_DATA_SIZE);
 	  d += sizeof (*b) - VLIB_BUFFER_PRE_DATA_SIZE;
 
-	  n_left = clib_min (vlib_buffer_length_in_chain (vm, b),
-			     512 - (sizeof (*b) - VLIB_BUFFER_PRE_DATA_SIZE));
+	  trace_length = vec_len (packet_trace);
+	  /* Copy the trace data length (may be zero) */
+	  clib_memcpy_fast (d, &trace_length, sizeof (trace_length));
+	  d += 2;
+
+	  /* Copy packet trace data (if any) */
+	  if (vec_len (packet_trace))
+	    clib_memcpy_fast (d, packet_trace, vec_len (packet_trace));
+
+	  d += vec_len (packet_trace);
+
+	  n_left = clib_min
+	    (vlib_buffer_length_in_chain (vm, b),
+	     16384 -
+	     ((sizeof (*b) - VLIB_BUFFER_PRE_DATA_SIZE) +
+	      (trace_length + 2)));
 	  /* Copy the packet data */
 	  while (1)
 	    {
@@ -1021,6 +1064,7 @@
 	  clib_spinlock_unlock_if_init (&pm->lock);
 	}
     }
+  vec_free (packet_trace);
 }
 
 static_always_inline u64
@@ -1991,6 +2035,9 @@
   int enabled = 0;
   int errorFlag = 0;
   clib_error_t *error = 0;
+  u32 node_index, add;
+  vlib_trace_main_t *tm;
+  vlib_trace_node_t *tn;
 
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
@@ -2087,6 +2134,27 @@
 	    }
 	  break;
 	}
+      else if (unformat (line_input, "buffer-trace %U %d",
+			 unformat_vlib_node, vm, &node_index, &add))
+	{
+	  if (vnet_trace_dummy == 0)
+	    vec_validate_aligned (vnet_trace_dummy, 2048,
+				  CLIB_CACHE_LINE_BYTES);
+	  vlib_cli_output (vm, "Buffer tracing of %d pkts from %U enabled...",
+			   add, format_vlib_node_name, vm, node_index);
+
+          /* *INDENT-OFF* */
+          foreach_vlib_main ((
+            {
+              tm = &this_vlib_main->trace_main;
+              tm->verbose = 0;  /* not sure this ever did anything... */
+              vec_validate (tm->nodes, node_index);
+              tn = tm->nodes + node_index;
+              tn->limit += add;
+              tm->trace_enable = 1;
+            }));
+          /* *INDENT-ON* */
+	}
 
       else
 	{
@@ -2174,7 +2242,11 @@
  * @cliexend
  * Example of how to start a dispatch trace capture:
  * @cliexstart{pcap dispatch trace on max 35 file dispatchTrace.pcap}
- * pcap dispatc capture on...
+ * pcap dispatch capture on...
+ * @cliexend
+ * Example of how to start a dispatch trace capture with buffer tracing
+ * @cliexstart{pcap dispatch trace on max 10000 file dispatchTrace.pcap buffer-trace dpdk-input 1000}
+ * pcap dispatch capture on...
  * @cliexend
  * Example of how to display the status of a tx packet capture in progress:
  * @cliexstart{pcap tx trace status}
@@ -2191,7 +2263,8 @@
 VLIB_CLI_COMMAND (pcap_dispatch_trace_command, static) = {
     .path = "pcap dispatch trace",
     .short_help =
-    "pcap dispatch trace [on|off] [max <nn>] [file <name>] [status]",
+    "pcap dispatch trace [on|off] [max <nn>] [file <name>] [status]\n"
+    "              [buffer-trace <input-node-name> <nn>]",
     .function = pcap_dispatch_trace_command_fn,
 };
 /* *INDENT-ON* */