From 2f9b0c05fca7ca829ea438da1d87e2bf93969500 Mon Sep 17 00:00:00 2001
From: Florin Coras <fcoras@cisco.com>
Date: Mon, 11 Sep 2017 20:54:15 -0400
Subject: dpdk: cli to check for buffer leakage

Use buffer pre_data and existing buffer trace trajectory code to
find out dpdk buffer leakages.

Change-Id: I26a5d8bd2f23d01cb6070ffc3ddcc6d3d863b575
Signed-off-by: Florin Coras <fcoras@cisco.com>
---
 src/plugins/dpdk/buffer.c        | 63 +++++++++++++++++++++++++++++++++++++++-
 src/plugins/dpdk/device/cli.c    | 53 +++++++++++++++++++++++++++++++++
 src/plugins/dpdk/device/device.c |  6 ++++
 src/plugins/dpdk/device/dpdk.h   |  5 ++++
 src/vlib/buffer.c                |  2 +-
 src/vnet/ip/ip4_forward.c        |  1 +
 src/vnet/tcp/tcp_output.c        | 10 ++++---
 7 files changed, 134 insertions(+), 6 deletions(-)

(limited to 'src')

diff --git a/src/plugins/dpdk/buffer.c b/src/plugins/dpdk/buffer.c
index 28af100af32..e09d80194ed 100644
--- a/src/plugins/dpdk/buffer.c
+++ b/src/plugins/dpdk/buffer.c
@@ -340,7 +340,7 @@ vlib_buffer_free_inline (vlib_main_t * vm,
       vlib_buffer_t *b;
 
       b = vlib_get_buffer (vm, buffers[i]);
-
+      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b);
       fl = vlib_buffer_get_buffer_free_list (vm, b, &fi);
 
       /* The only current use of this callback: multicast recycle */
@@ -493,6 +493,67 @@ buffer_state_validation_init (vlib_main_t * vm)
 VLIB_INIT_FUNCTION (buffer_state_validation_init);
 #endif
 
+#if CLI_DEBUG
+struct dpdk_validate_buf_result
+{
+  u32 invalid;
+  u32 uninitialized;
+};
+
+#define DPDK_TRAJECTORY_POISON 31
+
+static void
+dpdk_buffer_validate_trajectory (struct rte_mempool *mp, void *opaque,
+				 void *obj, unsigned obj_idx)
+{
+  vlib_buffer_t *b;
+  struct dpdk_validate_buf_result *counter = opaque;
+  b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
+  if (b->pre_data[0] != 0)
+    {
+      if (b->pre_data[0] == DPDK_TRAJECTORY_POISON)
+	counter->uninitialized++;
+      else
+	counter->invalid++;
+    }
+}
+
+int
+dpdk_buffer_validate_trajectory_all (u32 * uninitialized)
+{
+  dpdk_main_t *dm = &dpdk_main;
+  struct dpdk_validate_buf_result counter = { 0 };
+  int i;
+
+  for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
+    rte_mempool_obj_iter (dm->pktmbuf_pools[i],
+			  dpdk_buffer_validate_trajectory, &counter);
+  if (uninitialized)
+    *uninitialized = counter.uninitialized;
+  return counter.invalid;
+}
+
+static void
+dpdk_buffer_poison_trajectory (struct rte_mempool *mp, void *opaque,
+			       void *obj, unsigned obj_idx)
+{
+  vlib_buffer_t *b;
+  b = vlib_buffer_from_rte_mbuf ((struct rte_mbuf *) obj);
+  b->pre_data[0] = DPDK_TRAJECTORY_POISON;
+}
+
+void
+dpdk_buffer_poison_trajectory_all (void)
+{
+  dpdk_main_t *dm = &dpdk_main;
+  int i;
+
+  for (i = 0; i < vec_len (dm->pktmbuf_pools); i++)
+    rte_mempool_obj_iter (dm->pktmbuf_pools[i], dpdk_buffer_poison_trajectory,
+			  0);
+}
+#endif
+
 /* *INDENT-OFF* */
 VLIB_BUFFER_REGISTER_CALLBACKS (dpdk, static) = {
   .vlib_buffer_alloc_cb = &dpdk_buffer_alloc,
diff --git a/src/plugins/dpdk/device/cli.c b/src/plugins/dpdk/device/cli.c
index aeeb772d4fb..c9fcea5c8d5 100644
--- a/src/plugins/dpdk/device/cli.c
+++ b/src/plugins/dpdk/device/cli.c
@@ -1885,6 +1885,59 @@ VLIB_CLI_COMMAND (show_vpe_version_command, static) = {
 };
 /* *INDENT-ON* */
 
+#if CLI_DEBUG
+
+static clib_error_t *
+dpdk_validate_buffers_fn (vlib_main_t * vm, unformat_input_t * input,
+			  vlib_cli_command_t * cmd_arg)
+{
+  u32 n_invalid_bufs = 0, uninitialized = 0;
+  u32 is_poison = 0, is_test = 0;
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "poison"))
+	is_poison = 1;
+      else if (unformat (input, "trajectory"))
+	is_test = 1;
+      else
+	return clib_error_return (0, "unknown input `%U'",
+				  format_unformat_error, input);
+    }
+
+  if (VLIB_BUFFER_TRACE_TRAJECTORY == 0)
+    {
+      vlib_cli_output (vm, "Trajectory not enabled. Recompile with "
+		       "VLIB_BUFFER_TRACE_TRAJECTORY 1");
+      return 0;
+    }
+  if (is_poison)
+    {
+      dpdk_buffer_poison_trajectory_all ();
+    }
+  if (is_test)
+    {
+      n_invalid_bufs = dpdk_buffer_validate_trajectory_all (&uninitialized);
+      if (!n_invalid_bufs)
+	vlib_cli_output (vm, "All buffers are valid %d uninitialized",
+			 uninitialized);
+      else
+	vlib_cli_output (vm, "Found %d invalid buffers and %d uninitialized",
+			 n_invalid_bufs, uninitialized);
+    }
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (test_dpdk_buffers_command, static) =
+{
+  .path = "test dpdk buffers",
+  .short_help = "test dpdk buffers [poison] [trajectory]",
+  .function = dpdk_validate_buffers_fn,
+};
+/* *INDENT-ON* */
+
+#endif
+
 clib_error_t *
 dpdk_cli_init (vlib_main_t * vm)
 {
diff --git a/src/plugins/dpdk/device/device.c b/src/plugins/dpdk/device/device.c
index 97c136301df..aa134327373 100644
--- a/src/plugins/dpdk/device/device.c
+++ b/src/plugins/dpdk/device/device.c
@@ -462,6 +462,11 @@ dpdk_interface_tx (vlib_main_t * vm,
 
       or_flags = b0->flags | b1->flags | b2->flags | b3->flags;
 
+      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
+      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b1);
+      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b2);
+      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b3);
+
       if (or_flags & VLIB_BUFFER_NEXT_PRESENT)
 	{
 	  dpdk_validate_rte_mbuf (vm, b0, 1);
@@ -556,6 +561,7 @@ dpdk_interface_tx (vlib_main_t * vm,
       from++;
 
       b0 = vlib_get_buffer (vm, bi0);
+      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
 
       dpdk_validate_rte_mbuf (vm, b0, 1);
 
diff --git a/src/plugins/dpdk/device/dpdk.h b/src/plugins/dpdk/device/dpdk.h
index 849e687ba44..9762c7137f5 100644
--- a/src/plugins/dpdk/device/dpdk.h
+++ b/src/plugins/dpdk/device/dpdk.h
@@ -467,6 +467,11 @@ admin_up_down_process (vlib_main_t * vm,
 clib_error_t *dpdk_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
 				       unsigned socket_id);
 
+#if CLI_DEBUG
+int dpdk_buffer_validate_trajectory_all (u32 * uninitialized);
+void dpdk_buffer_poison_trajectory_all (void);
+#endif
+
 #endif /* __included_dpdk_h__ */
 
 /*
diff --git a/src/vlib/buffer.c b/src/vlib/buffer.c
index a5ec0e0a495..7399b618ed4 100644
--- a/src/vlib/buffer.c
+++ b/src/vlib/buffer.c
@@ -686,7 +686,7 @@ vlib_buffer_free_inline (vlib_main_t * vm,
       u32 bi = buffers[i];
 
       b = vlib_get_buffer (vm, bi);
-
+      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b);
       fl = vlib_buffer_get_buffer_free_list (vm, b, &fi);
 
       /* The only current use of this callback: multicast recycle */
diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c
index b3de1201abc..c526003c382 100755
--- a/src/vnet/ip/ip4_forward.c
+++ b/src/vnet/ip/ip4_forward.c
@@ -2131,6 +2131,7 @@ ip4_arp_inline (vlib_main_t * vm,
 
 	      vlib_buffer_copy_trace_flag (vm, p0, bi0);
 	      b0 = vlib_get_buffer (vm, bi0);
+	      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
 	      vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
 
 	      vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c
index 9cb3e77937e..b843c926afe 100644
--- a/src/vnet/tcp/tcp_output.c
+++ b/src/vnet/tcp/tcp_output.c
@@ -439,14 +439,16 @@ tcp_init_mss (tcp_connection_t * tc)
 always_inline int
 tcp_alloc_tx_buffers (tcp_main_t * tm, u8 thread_index, u32 n_free_buffers)
 {
+  vlib_main_t *vm = vlib_get_main ();
   u32 current_length = vec_len (tm->tx_buffers[thread_index]);
+  u32 n_allocated;
 
   vec_validate (tm->tx_buffers[thread_index],
 		current_length + n_free_buffers - 1);
-  _vec_len (tm->tx_buffers[thread_index]) = current_length
-    + vlib_buffer_alloc (vlib_get_main (),
-			 &tm->tx_buffers[thread_index][current_length],
-			 n_free_buffers);
+  n_allocated =
+    vlib_buffer_alloc (vm, &tm->tx_buffers[thread_index][current_length],
+		       n_free_buffers);
+  _vec_len (tm->tx_buffers[thread_index]) = current_length + n_allocated;
   /* buffer shortage, report failure */
   if (vec_len (tm->tx_buffers[thread_index]) == 0)
     {
-- 
cgit