vlib: fix trace number accounting

When using classifier to filter traces, not all packets will be traced.
In that case, we should only count traced packets.

Type: fix

Change-Id: I87d1e217b580ebff8c6ade7860eb43950420ae78
Signed-off-by: Benoît Ganne <bganne@cisco.com>
diff --git a/src/vnet/bonding/device.c b/src/vnet/bonding/device.c
index bc18586..7ce5ad8 100644
--- a/src/vnet/bonding/device.c
+++ b/src/vnet/bonding/device.c
@@ -651,25 +651,28 @@
 
   while (n_trace > 0 && n_left > 0)
     {
-      bond_packet_trace_t *t0;
-      ethernet_header_t *eth;
-      u32 next0 = 0;
+      if (PREDICT_TRUE
+	  (vlib_trace_buffer (vm, node, 0, b[0], 0 /* follow_chain */ )))
+	{
+	  bond_packet_trace_t *t0;
+	  ethernet_header_t *eth;
 
-      vlib_trace_buffer (vm, node, next0, b[0], 0 /* follow_chain */ );
-      vlib_set_trace_count (vm, node, --n_trace);
-      t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
-      eth = vlib_buffer_get_current (b[0]);
-      t0->ethernet = *eth;
-      t0->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
-      if (!h)
-	{
-	  t0->bond_sw_if_index = *vec_elt_at_index (bif->active_members, 0);
-	}
-      else
-	{
-	  t0->bond_sw_if_index =
-	    *vec_elt_at_index (bif->active_members, h[0]);
-	  h++;
+	  vlib_set_trace_count (vm, node, --n_trace);
+	  t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
+	  eth = vlib_buffer_get_current (b[0]);
+	  t0->ethernet = *eth;
+	  t0->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
+	  if (!h)
+	    {
+	      t0->bond_sw_if_index =
+		*vec_elt_at_index (bif->active_members, 0);
+	    }
+	  else
+	    {
+	      t0->bond_sw_if_index =
+		*vec_elt_at_index (bif->active_members, h[0]);
+	      h++;
+	    }
 	}
       b++;
       n_left--;
diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c
index 196c088..61d4ce2 100644
--- a/src/vnet/devices/af_packet/node.c
+++ b/src/vnet/devices/af_packet/node.c
@@ -310,11 +310,11 @@
 
 	  /* trace */
 	  VLIB_BUFFER_TRACE_TRAJECTORY_INIT (first_b0);
-	  if (PREDICT_FALSE (n_trace > 0))
+	  if (PREDICT_FALSE
+	      (n_trace > 0 && vlib_trace_buffer (vm, node, next0, first_b0,
+						 /* follow_chain */ 0)))
 	    {
 	      af_packet_input_trace_t *tr;
-	      vlib_trace_buffer (vm, node, next0, first_b0,	/* follow_chain */
-				 0);
 	      vlib_set_trace_count (vm, node, --n_trace);
 	      tr = vlib_add_trace (vm, node, first_b0, sizeof (*tr));
 	      tr->next_index = next0;
diff --git a/src/vnet/devices/virtio/node.c b/src/vnet/devices/virtio/node.c
index 94bf097..91e788e 100644
--- a/src/vnet/devices/virtio/node.c
+++ b/src/vnet/devices/virtio/node.c
@@ -388,11 +388,10 @@
 	  /* trace */
 	  VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
 
-	  if (PREDICT_FALSE (n_trace > 0))
+	  if (PREDICT_FALSE (n_trace > 0 && vlib_trace_buffer (vm, node, next0, b0,	/* follow_chain */
+							       1)))
 	    {
 	      virtio_input_trace_t *tr;
-	      vlib_trace_buffer (vm, node, next0, b0,
-				 /* follow_chain */ 1);
 	      vlib_set_trace_count (vm, node, --n_trace);
 	      tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
 	      tr->next_index = next0;
diff --git a/src/vnet/devices/virtio/vhost_user_input.c b/src/vnet/devices/virtio/vhost_user_input.c
index da4937b..53230a6 100644
--- a/src/vnet/devices/virtio/vhost_user_input.c
+++ b/src/vnet/devices/virtio/vhost_user_input.c
@@ -540,10 +540,10 @@
       b_head->total_length_not_including_first_buffer = 0;
       b_head->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
 
-      if (PREDICT_FALSE (n_trace))
+      if (PREDICT_FALSE
+	  (n_trace > 0 && vlib_trace_buffer (vm, node, next_index, b_head,
+					     /* follow_chain */ 0)))
 	{
-	  vlib_trace_buffer (vm, node, next_index, b_head,
-			     /* follow_chain */ 0);
 	  vhost_trace_t *t0 =
 	    vlib_add_trace (vm, node, b_head, sizeof (t0[0]));
 	  vhost_user_rx_trace (t0, vui, qid, b_head, txvq, last_avail_idx);
@@ -1362,17 +1362,19 @@
       b = cpu->rx_buffers_pdesc;
       while (n_trace && left)
 	{
-	  vhost_trace_t *t0;
-
-	  vlib_trace_buffer (vm, node, next_index, b[0],
-			     /* follow_chain */ 0);
-	  t0 = vlib_add_trace (vm, node, b[0], sizeof (t0[0]));
-	  b++;
-	  vhost_user_rx_trace_packed (t0, vui, qid, txvq, last_used_idx);
-	  last_used_idx = (last_used_idx + 1) & mask;
-	  n_trace--;
+	  if (PREDICT_TRUE
+	      (vlib_trace_buffer
+	       (vm, node, next_index, b[0], /* follow_chain */ 0)))
+	    {
+	      vhost_trace_t *t0;
+	      t0 = vlib_add_trace (vm, node, b[0], sizeof (t0[0]));
+	      vhost_user_rx_trace_packed (t0, vui, qid, txvq, last_used_idx);
+	      last_used_idx = (last_used_idx + 1) & mask;
+	      n_trace--;
+	      vlib_set_trace_count (vm, node, n_trace);
+	    }
 	  left--;
-	  vlib_set_trace_count (vm, node, n_trace);
+	  b++;
 	}
     }
 
diff --git a/src/vnet/ethernet/p2p_ethernet_input.c b/src/vnet/ethernet/p2p_ethernet_input.c
index 7e5f7ca..3e9589e 100644
--- a/src/vnet/ethernet/p2p_ethernet_input.c
+++ b/src/vnet/ethernet/p2p_ethernet_input.c
@@ -119,11 +119,12 @@
 	      vnet_buffer (b0)->sw_if_index[VLIB_RX] = rx0;
 	      n_p2p_ethernet_packets += 1;
 
-	      if (PREDICT_FALSE (n_trace > 0))
+	      if (PREDICT_FALSE
+		  (n_trace > 0
+		   && vlib_trace_buffer (vm, node, next_index, b0,
+					 1 /* follow_chain */ )))
 		{
 		  p2p_ethernet_trace_t *t0;
-		  vlib_trace_buffer (vm, node, next_index, b0,
-				     1 /* follow_chain */ );
 		  vlib_set_trace_count (vm, node, --n_trace);
 		  t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
 		  t0->sw_if_index = sw_if_index0;
@@ -140,11 +141,12 @@
 	      vnet_buffer (b1)->sw_if_index[VLIB_RX] = rx1;
 	      n_p2p_ethernet_packets += 1;
 
-	      if (PREDICT_FALSE (n_trace > 0))
+	      if (PREDICT_FALSE
+		  (n_trace > 0
+		   && vlib_trace_buffer (vm, node, next_index, b1,
+					 1 /* follow_chain */ )))
 		{
 		  p2p_ethernet_trace_t *t1;
-		  vlib_trace_buffer (vm, node, next_index, b1,
-				     1 /* follow_chain */ );
 		  vlib_set_trace_count (vm, node, --n_trace);
 		  t1 = vlib_add_trace (vm, node, b1, sizeof (*t1));
 		  t1->sw_if_index = sw_if_index1;
@@ -195,11 +197,12 @@
 	      vnet_buffer (b0)->sw_if_index[VLIB_RX] = rx0;
 	      n_p2p_ethernet_packets += 1;
 
-	      if (PREDICT_FALSE (n_trace > 0))
+	      if (PREDICT_FALSE
+		  (n_trace > 0
+		   && vlib_trace_buffer (vm, node, next_index, b0,
+					 1 /* follow_chain */ )))
 		{
 		  p2p_ethernet_trace_t *t0;
-		  vlib_trace_buffer (vm, node, next_index, b0,
-				     1 /* follow_chain */ );
 		  vlib_set_trace_count (vm, node, --n_trace);
 		  t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
 		  t0->sw_if_index = sw_if_index0;
@@ -228,6 +231,7 @@
 
   vlib_node_increment_counter (vm, p2p_ethernet_input_node.index,
 			       P2PE_ERROR_HITS, n_p2p_ethernet_packets);
+
   return frame->n_vectors;
 }
 
diff --git a/src/vnet/interface_output.c b/src/vnet/interface_output.c
index 52c07ac..65bc4a4 100644
--- a/src/vnet/interface_output.c
+++ b/src/vnet/interface_output.c
@@ -800,19 +800,21 @@
 	  node->flags |= VLIB_NODE_FLAG_TRACE;
 	  while (n_trace && n_left)
 	    {
-	      vlib_trace_buffer (vm, node, 0 /* next_index */ ,
-				 b[0], 0 /* follow chain */ );
-	      /*
-	       * Here we have a wireshark dissector problem.
-	       * Packets may be well-formed, or not. We
-	       * must not blow chunks in any case.
-	       *
-	       * Try to produce trace records which will help
-	       * folks understand what's going on.
-	       */
-	      drop_catchup_trace (vm, node, b[0]);
-
-	      n_trace--;
+	      if (PREDICT_TRUE
+		  (vlib_trace_buffer (vm, node, 0 /* next_index */ , b[0],
+				      0 /* follow chain */ )))
+		{
+		  /*
+		   * Here we have a wireshark dissector problem.
+		   * Packets may be well-formed, or not. We
+		   * must not blow chunks in any case.
+		   *
+		   * Try to produce trace records which will help
+		   * folks understand what's going on.
+		   */
+		  drop_catchup_trace (vm, node, b[0]);
+		  n_trace--;
+		}
 	      n_left--;
 	      b++;
 	    }
diff --git a/src/vnet/ip/punt_node.c b/src/vnet/ip/punt_node.c
index 23c4cc4..90953e6 100644
--- a/src/vnet/ip/punt_node.c
+++ b/src/vnet/ip/punt_node.c
@@ -573,10 +573,11 @@
       goto error;
     }
 
-  if (PREDICT_FALSE (n_trace > 0))
+  if (PREDICT_FALSE
+      (n_trace > 0
+       && vlib_trace_buffer (vm, node, next_index, b, 1 /* follow_chain */ )))
     {
       punt_trace_t *t;
-      vlib_trace_buffer (vm, node, next_index, b, 1 /* follow_chain */ );
       vlib_set_trace_count (vm, node, --n_trace);
       t = vlib_add_trace (vm, node, b, sizeof (*t));
       t->sw_if_index = packetdesc.sw_if_index;
@@ -590,6 +591,7 @@
   vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next, n_left_to_next,
 				   bi, next_index);
   vlib_put_next_frame (vm, node, next, n_left_to_next);
+
   return 1;
 
 error:
diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c
index c8f3d9f..d5cf929 100644
--- a/src/vnet/pg/input.c
+++ b/src/vnet/pg/input.c
@@ -1454,15 +1454,16 @@
   return s;
 }
 
-static void
+static int
 pg_input_trace (pg_main_t * pg,
 		vlib_node_runtime_t * node, u32 stream_index, u32 next_index,
-		u32 * buffers, u32 n_buffers)
+		u32 * buffers, const u32 n_buffers, const u32 n_trace)
 {
   vlib_main_t *vm = vlib_get_main ();
   u32 *b, n_left;
+  u32 n_trace0 = 0, n_trace1 = 0;
 
-  n_left = n_buffers;
+  n_left = clib_min (n_buffers, n_trace);
   b = buffers;
 
   while (n_left >= 2)
@@ -1479,8 +1480,10 @@
       b0 = vlib_get_buffer (vm, bi0);
       b1 = vlib_get_buffer (vm, bi1);
 
-      vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 1);
-      vlib_trace_buffer (vm, node, next_index, b1, /* follow_chain */ 1);
+      n_trace0 +=
+	vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 1);
+      n_trace1 +=
+	vlib_trace_buffer (vm, node, next_index, b1, /* follow_chain */ 1);
 
       t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
       t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
@@ -1517,7 +1520,8 @@
 
       b0 = vlib_get_buffer (vm, bi0);
 
-      vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 1);
+      n_trace0 +=
+	vlib_trace_buffer (vm, node, next_index, b0, /* follow_chain */ 1);
       t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
 
       t0->stream_index = stream_index;
@@ -1528,6 +1532,8 @@
       clib_memcpy_fast (t0->buffer.pre_data, b0->data,
 			sizeof (t0->buffer.pre_data));
     }
+
+  return n_trace - n_trace0 - n_trace1;
 }
 
 static_always_inline void
@@ -1714,11 +1720,12 @@
 	}
 
       n_trace = vlib_get_trace_count (vm, node);
-      if (n_trace > 0)
+      if (PREDICT_FALSE (n_trace > 0))
 	{
-	  u32 n = clib_min (n_trace, n_this_frame);
-	  pg_input_trace (pg, node, s - pg->streams, next_index, to_next, n);
-	  vlib_set_trace_count (vm, node, n_trace - n);
+	  n_trace =
+	    pg_input_trace (pg, node, s - pg->streams, next_index, to_next,
+			    n_this_frame, n_trace);
+	  vlib_set_trace_count (vm, node, n_trace);
 	}
       n_packets_to_generate -= n_this_frame;
       n_packets_generated += n_this_frame;
diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c
index ec2f936..8a350d4 100644
--- a/src/vnet/session/session_node.c
+++ b/src/vnet/session/session_node.c
@@ -569,19 +569,23 @@
 			u32 next_index, u32 * to_next, u16 n_segs,
 			session_t * s, u32 n_trace)
 {
-  session_queue_trace_t *t;
-  vlib_buffer_t *b;
-  int i;
-
-  for (i = 0; i < clib_min (n_trace, n_segs); i++)
+  while (n_trace && n_segs)
     {
-      b = vlib_get_buffer (vm, to_next[i]);
-      vlib_trace_buffer (vm, node, next_index, b, 1 /* follow_chain */ );
-      t = vlib_add_trace (vm, node, b, sizeof (*t));
-      t->session_index = s->session_index;
-      t->server_thread_index = s->thread_index;
+      vlib_buffer_t *b = vlib_get_buffer (vm, to_next[0]);
+      if (PREDICT_TRUE
+	  (vlib_trace_buffer
+	   (vm, node, next_index, b, 1 /* follow_chain */ )))
+	{
+	  session_queue_trace_t *t =
+	    vlib_add_trace (vm, node, b, sizeof (*t));
+	  t->session_index = s->session_index;
+	  t->server_thread_index = s->thread_index;
+	  n_trace--;
+	}
+      to_next++;
+      n_segs--;
     }
-  vlib_set_trace_count (vm, node, n_trace - i);
+  vlib_set_trace_count (vm, node, n_trace);
 }
 
 always_inline void
diff --git a/src/vnet/unix/tuntap.c b/src/vnet/unix/tuntap.c
index 72c4f73..6834ee8 100644
--- a/src/vnet/unix/tuntap.c
+++ b/src/vnet/unix/tuntap.c
@@ -378,11 +378,9 @@
 
     vlib_set_next_frame_buffer (vm, node, next_index, bi);
 
-    if (n_trace > 0)
-      {
-	vlib_trace_buffer (vm, node, next_index, b, /* follow_chain */ 1);
-	vlib_set_trace_count (vm, node, n_trace - 1);
-      }
+    if (PREDICT_FALSE (n_trace > 0 && vlib_trace_buffer (vm, node, next_index, b,	/* follow_chain */
+							 1)))
+      vlib_set_trace_count (vm, node, n_trace - 1);
   }
 
   return 1;