Add interface rx pcap tracing 49/12749/1
authorDave Barach <dbarach@cisco.com>
Fri, 25 May 2018 21:36:05 +0000 (17:36 -0400)
committerDave Barach <dbarach@cisco.com>
Fri, 25 May 2018 21:36:44 +0000 (17:36 -0400)
Should cost at most 1 clock per frame when not enabled.

Add "pcap rx trace..." debug CLI, refactored "pcap tx trace" debug CLI
to avoid duplicating code.

Change-Id: I19ac75d1cf94a6a24c98facbf0753381d37963ea
Signed-off-by: Dave Barach <dbarach@cisco.com>
src/plugins/dpdk/device/cli.c
src/plugins/dpdk/device/device.c
src/plugins/dpdk/device/dpdk.h
src/plugins/dpdk/device/node.c
src/vnet/unix/pcap.h

index 08bf0c9..151a6f4 100644 (file)
@@ -88,9 +88,10 @@ done:
   return error;
 }
 
-static clib_error_t *
-pcap_trace_command_fn (vlib_main_t * vm,
-                      unformat_input_t * input, vlib_cli_command_t * cmd)
+static inline clib_error_t *
+pcap_trace_command_internal (vlib_main_t * vm,
+                            unformat_input_t * input,
+                            vlib_cli_command_t * cmd, int rx_tx)
 {
 #define PCAP_DEF_PKT_TO_CAPTURE (100)
 
@@ -111,7 +112,7 @@ pcap_trace_command_fn (vlib_main_t * vm,
     {
       if (unformat (line_input, "on"))
        {
-         if (dm->tx_pcap_enable == 0)
+         if (dm->pcap[rx_tx].pcap_enable == 0)
            {
              enabled = 1;
            }
@@ -124,22 +125,24 @@ pcap_trace_command_fn (vlib_main_t * vm,
        }
       else if (unformat (line_input, "off"))
        {
-         if (dm->tx_pcap_enable)
+         if (dm->pcap[rx_tx].pcap_enable)
            {
-             vlib_cli_output (vm, "captured %d pkts...",
-                              dm->pcap_main.n_packets_captured + 1);
-             if (dm->pcap_main.n_packets_captured)
+             vlib_cli_output
+               (vm, "captured %d pkts...",
+                dm->pcap[rx_tx].pcap_main.n_packets_captured);
+             if (dm->pcap[rx_tx].pcap_main.n_packets_captured)
                {
-                 dm->pcap_main.n_packets_to_capture =
-                   dm->pcap_main.n_packets_captured;
-                 error = pcap_write (&dm->pcap_main);
+                 dm->pcap[rx_tx].pcap_main.n_packets_to_capture =
+                   dm->pcap[rx_tx].pcap_main.n_packets_captured;
+                 error = pcap_write (&dm->pcap[rx_tx].pcap_main);
                  if (error)
                    clib_error_report (error);
                  else
-                   vlib_cli_output (vm, "saved to %s...", dm->pcap_filename);
+                   vlib_cli_output (vm, "saved to %s...",
+                                    dm->pcap[rx_tx].pcap_filename);
                }
 
-             dm->tx_pcap_enable = 0;
+             dm->pcap[rx_tx].pcap_enable = 0;
            }
          else
            {
@@ -150,29 +153,31 @@ pcap_trace_command_fn (vlib_main_t * vm,
        }
       else if (unformat (line_input, "max %d", &max))
        {
-         if (dm->tx_pcap_enable)
+         if (dm->pcap[rx_tx].pcap_enable)
            {
-             vlib_cli_output (vm,
-                              "can't change max value while pcap tx capture active...");
+             vlib_cli_output
+               (vm,
+                "can't change max value while pcap tx capture active...");
              errorFlag = 1;
              break;
            }
+         dm->pcap[rx_tx].pcap_main.n_packets_to_capture = max;
        }
       else if (unformat (line_input, "intfc %U",
                         unformat_vnet_sw_interface, dm->vnet_main,
-                        &dm->pcap_sw_if_index))
+                        &dm->pcap[rx_tx].pcap_sw_if_index))
        ;
 
       else if (unformat (line_input, "intfc any"))
        {
-         dm->pcap_sw_if_index = 0;
+         dm->pcap[rx_tx].pcap_sw_if_index = 0;
        }
       else if (unformat (line_input, "file %s", &filename))
        {
-         if (dm->tx_pcap_enable)
+         if (dm->pcap[rx_tx].pcap_enable)
            {
-             vlib_cli_output (vm,
-                              "can't change file while pcap tx capture active...");
+             vlib_cli_output
+               (vm, "can't change file while pcap tx capture active...");
              errorFlag = 1;
              break;
            }
@@ -183,8 +188,7 @@ pcap_trace_command_fn (vlib_main_t * vm,
            {
              vlib_cli_output (vm, "illegal characters in filename '%s'",
                               filename);
-             vlib_cli_output (vm,
-                              "Hint: Only filename, do not enter directory structure.");
+             vlib_cli_output (vm, "Hint: .. and / are not allowed.");
              vec_free (filename);
              errorFlag = 1;
              break;
@@ -195,38 +199,41 @@ pcap_trace_command_fn (vlib_main_t * vm,
        }
       else if (unformat (line_input, "status"))
        {
-         if (dm->pcap_sw_if_index == 0)
+         if (dm->pcap[rx_tx].pcap_sw_if_index == 0)
            {
-             vlib_cli_output (vm, "max is %d for any interface to file %s",
-                              dm->
-                              pcap_pkts_to_capture ? dm->pcap_pkts_to_capture
-                              : PCAP_DEF_PKT_TO_CAPTURE,
-                              dm->
-                              pcap_filename ? dm->pcap_filename : (u8 *)
-                              "/tmp/vpe.pcap");
+             vlib_cli_output
+               (vm, "max is %d for any interface to file %s",
+                dm->pcap_pkts_to_capture ?
+                dm->pcap[rx_tx].pcap_pkts_to_capture
+                : PCAP_DEF_PKT_TO_CAPTURE,
+                dm->pcap_filename ?
+                dm->pcap[rx_tx].pcap_filename : (u8 *) "/tmp/vpe.pcap");
            }
          else
            {
              vlib_cli_output (vm, "max is %d for interface %U to file %s",
-                              dm->
-                              pcap_pkts_to_capture ? dm->pcap_pkts_to_capture
+                              dm->pcap[rx_tx].pcap_pkts_to_capture
+                              ? dm->pcap_pkts_to_capture
                               : PCAP_DEF_PKT_TO_CAPTURE,
                               format_vnet_sw_if_index_name, dm->vnet_main,
                               dm->pcap_sw_if_index,
-                              dm->
-                              pcap_filename ? dm->pcap_filename : (u8 *)
+                              dm->pcap[rx_tx].pcap_filename
+                              ? dm->pcap[rx_tx].pcap_filename : (u8 *)
                               "/tmp/vpe.pcap");
            }
 
-         if (dm->tx_pcap_enable == 0)
+         if (dm->pcap[rx_tx].pcap_enable == 0)
            {
-             vlib_cli_output (vm, "pcap tx capture is off...");
+             vlib_cli_output (vm, "pcap %s capture is off...",
+                              (rx_tx == VLIB_RX) ? "rx" : "tx");
            }
          else
            {
-             vlib_cli_output (vm, "pcap tx capture is on: %d of %d pkts...",
-                              dm->pcap_main.n_packets_captured,
-                              dm->pcap_main.n_packets_to_capture);
+             vlib_cli_output (vm, "pcap %s capture is on: %d of %d pkts...",
+                              (rx_tx == VLIB_RX) ? "rx" : "tx",
+                              dm->pcap[rx_tx].pcap_main.n_packets_captured,
+                              dm->pcap[rx_tx].
+                              pcap_main.n_packets_to_capture);
            }
          break;
        }
@@ -247,42 +254,62 @@ pcap_trace_command_fn (vlib_main_t * vm,
       /* Since no error, save configured values. */
       if (chroot_filename)
        {
-         if (dm->pcap_filename)
-           vec_free (dm->pcap_filename);
+         if (dm->pcap[rx_tx].pcap_filename)
+           vec_free (dm->pcap[rx_tx].pcap_filename);
          vec_add1 (chroot_filename, 0);
-         dm->pcap_filename = chroot_filename;
+         dm->pcap[rx_tx].pcap_filename = chroot_filename;
        }
 
       if (max)
-       dm->pcap_pkts_to_capture = max;
+       dm->pcap[rx_tx].pcap_pkts_to_capture = max;
 
 
       if (enabled)
        {
-         if (dm->pcap_filename == 0)
-           dm->pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
-
-         memset (&dm->pcap_main, 0, sizeof (dm->pcap_main));
-         dm->pcap_main.file_name = (char *) dm->pcap_filename;
-         dm->pcap_main.n_packets_to_capture = PCAP_DEF_PKT_TO_CAPTURE;
-         if (dm->pcap_pkts_to_capture)
-           dm->pcap_main.n_packets_to_capture = dm->pcap_pkts_to_capture;
-
-         dm->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
-         dm->tx_pcap_enable = 1;
+         if (dm->pcap[rx_tx].pcap_filename == 0)
+           dm->pcap[rx_tx].pcap_filename = format (0, "/tmp/vpe.pcap%c", 0);
+
+         memset (&dm->pcap[rx_tx].pcap_main, 0,
+                 sizeof (dm->pcap[rx_tx].pcap_main));
+         dm->pcap[rx_tx].pcap_main.file_name =
+           (char *) dm->pcap[rx_tx].pcap_filename;
+         dm->pcap[rx_tx].pcap_main.n_packets_to_capture
+           = PCAP_DEF_PKT_TO_CAPTURE;
+         if (dm->pcap[rx_tx].pcap_pkts_to_capture)
+           dm->pcap[rx_tx].pcap_main.n_packets_to_capture
+             = dm->pcap[rx_tx].pcap_pkts_to_capture;
+
+         dm->pcap[rx_tx].pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
+         dm->pcap[rx_tx].pcap_enable = 1;
          vlib_cli_output (vm, "pcap tx capture on...");
        }
     }
   else if (chroot_filename)
     vec_free (chroot_filename);
 
-
   return error;
 }
 
+static clib_error_t *
+pcap_rx_trace_command_fn (vlib_main_t * vm,
+                         unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  return pcap_trace_command_internal (vm, input, cmd, VLIB_RX);
+}
+
+static clib_error_t *
+pcap_tx_trace_command_fn (vlib_main_t * vm,
+                         unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  return pcap_trace_command_internal (vm, input, cmd, VLIB_TX);
+}
+
+
 /*?
  * This command is used to start or stop a packet capture, or show
- * the status of packet capture.
+ * the status of packet capture. Note that both "pcap rx trace" and
+ * "pcap tx trace" are implemented. The command syntax is identical,
+ * simply substitute rx for tx as needed.
  *
  * This command has the following optional parameters:
  *
@@ -334,11 +361,18 @@ pcap_trace_command_fn (vlib_main_t * vm,
  * @cliexend
 ?*/
 /* *INDENT-OFF* */
-VLIB_CLI_COMMAND (pcap_trace_command, static) = {
+
+VLIB_CLI_COMMAND (pcap_tx_trace_command, static) = {
     .path = "pcap tx trace",
     .short_help =
     "pcap tx trace [on|off] [max <nn>] [intfc <interface>|any] [file <name>] [status]",
-    .function = pcap_trace_command_fn,
+    .function = pcap_tx_trace_command_fn,
+};
+VLIB_CLI_COMMAND (pcap_rx_trace_command, static) = {
+    .path = "pcap rx trace",
+    .short_help =
+    "pcap rx trace [on|off] [max <nn>] [intfc <interface>|any] [file <name>] [status]",
+    .function = pcap_rx_trace_command_fn,
 };
 /* *INDENT-ON* */
 
index 0ac798f..5409fe4 100644 (file)
@@ -351,16 +351,17 @@ CLIB_MULTIARCH_FN (dpdk_interface_tx) (vlib_main_t * vm,
   ASSERT (n_packets <= VLIB_FRAME_SIZE);
 
   /* TX PCAP tracing */
-  if (PREDICT_FALSE (dm->tx_pcap_enable))
+  if (PREDICT_FALSE (dm->pcap[VLIB_TX].pcap_enable))
     {
       n_left = n_packets;
       while (n_left > 0)
        {
          u32 bi0 = from[0];
          vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
-         if (dm->pcap_sw_if_index == 0 ||
-             dm->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_TX])
-           pcap_add_buffer (&dm->pcap_main, vm, bi0, 512);
+         if (dm->pcap[VLIB_TX].pcap_sw_if_index == 0 ||
+             dm->pcap[VLIB_TX].pcap_sw_if_index
+             == vnet_buffer (b0)->sw_if_index[VLIB_TX])
+           pcap_add_buffer (&dm->pcap[VLIB_TX].pcap_main, vm, bi0, 512);
          from++;
          n_left--;
        }
index eed1126..c60312e 100644 (file)
@@ -378,6 +378,15 @@ typedef struct
   vlib_buffer_t buffer_template;
 } dpdk_per_thread_data_t;
 
+typedef struct
+{
+  int pcap_enable;
+  pcap_main_t pcap_main;
+  u8 *pcap_filename;
+  u32 pcap_sw_if_index;
+  u32 pcap_pkts_to_capture;
+} dpdk_pcap_t;
+
 typedef struct
 {
 
@@ -392,8 +401,10 @@ typedef struct
   /* buffer flags template, configurable to enable/disable tcp / udp cksum */
   u32 buffer_flags_template;
 
-  /* pcap tracing [only works if (CLIB_DEBUG > 0)] */
-  int tx_pcap_enable;
+  /* pcap tracing */
+  dpdk_pcap_t pcap[VLIB_N_RX_TX];
+
+  int pcap_enable;
   pcap_main_t pcap_main;
   u8 *pcap_filename;
   u32 pcap_sw_if_index;
index a1acc1f..daccf73 100644 (file)
@@ -553,7 +553,7 @@ dpdk_device_input (vlib_main_t * vm, dpdk_main_t * dm, dpdk_device_t * xd,
                               n_rx_packets);
 
   /* packet trace if enabled */
-  if ((n_trace = vlib_get_trace_count (vm, node)))
+  if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, node))))
     {
       n_left = n_rx_packets;
       buffers = ptd->buffers;
@@ -584,6 +584,48 @@ dpdk_device_input (vlib_main_t * vm, dpdk_main_t * dm, dpdk_device_t * xd,
       vlib_set_trace_count (vm, node, n_trace);
     }
 
+  /* rx pcap capture if enabled */
+  if (PREDICT_FALSE (dm->pcap[VLIB_RX].pcap_enable))
+    {
+      u32 bi0;
+      n_left = n_rx_packets;
+      buffers = ptd->buffers;
+      while (n_left)
+       {
+         bi0 = buffers[0];
+         b0 = vlib_get_buffer (vm, bi0);
+         buffers++;
+
+         if (dm->pcap[VLIB_RX].pcap_sw_if_index == 0 ||
+             dm->pcap[VLIB_RX].pcap_sw_if_index
+             == vnet_buffer (b0)->sw_if_index[VLIB_RX])
+           {
+             struct rte_mbuf *mb;
+             i16 data_start;
+             i32 temp_advance;
+
+             /*
+              * Note: current_data will have advanced
+              * when we skip ethernet input.
+              * Temporarily back up to the original DMA
+              * target, so we capture a valid ethernet frame
+              */
+             mb = rte_mbuf_from_vlib_buffer (b0);
+
+             /* Figure out the original data_start */
+             data_start = (mb->buf_addr + mb->data_off) - (void *) b0->data;
+             /* Back up that far */
+             temp_advance = b0->current_data - data_start;
+             vlib_buffer_advance (b0, -temp_advance);
+             /* Trace the packet */
+             pcap_add_buffer (&dm->pcap[VLIB_RX].pcap_main, vm, bi0, 512);
+             /* and advance again */
+             vlib_buffer_advance (b0, temp_advance);
+           }
+         n_left--;
+       }
+    }
+
   vlib_increment_combined_counter
     (vnet_get_main ()->interface_main.combined_sw_if_counters
      + VNET_INTERFACE_COUNTER_RX, thread_index, xd->sw_if_index,
index 7d55db3..1ab1531 100644 (file)
@@ -211,23 +211,21 @@ pcap_add_buffer (pcap_main_t * pm,
   f64 time_now = vlib_time_now (vm);
   void *d;
 
-  d = pcap_add_packet (pm, time_now, n_left, n);
-  while (1)
+  if (PREDICT_TRUE (pm->n_packets_captured < pm->n_packets_to_capture))
     {
-      u32 copy_length = clib_min ((u32) n_left, b->current_length);
-      clib_memcpy (d, b->data + b->current_data, copy_length);
-      n_left -= b->current_length;
-      if (n_left <= 0)
-       break;
-      d += b->current_length;
-      ASSERT (b->flags & VLIB_BUFFER_NEXT_PRESENT);
-      b = vlib_get_buffer (vm, b->next_buffer);
+      d = pcap_add_packet (pm, time_now, n_left, n);
+      while (1)
+       {
+         u32 copy_length = clib_min ((u32) n_left, b->current_length);
+         clib_memcpy (d, b->data + b->current_data, copy_length);
+         n_left -= b->current_length;
+         if (n_left <= 0)
+           break;
+         d += b->current_length;
+         ASSERT (b->flags & VLIB_BUFFER_NEXT_PRESENT);
+         b = vlib_get_buffer (vm, b->next_buffer);
+       }
     }
-
-  /** Flush output vector. */
-  if (vec_len (pm->pcap_data) >= 64 * 1024
-      || pm->n_packets_captured >= pm->n_packets_to_capture)
-    pcap_write (pm);
 }
 
 #endif /* included_vnet_pcap_h */