From c6f186b23d00685b3e9f132ba79a5cb44f0a44c0 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Fri, 25 May 2018 17:36:05 -0400 Subject: Add interface rx pcap tracing 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 --- src/plugins/dpdk/device/cli.c | 152 ++++++++++++++++++++++++--------------- src/plugins/dpdk/device/device.c | 9 +-- src/plugins/dpdk/device/dpdk.h | 15 +++- src/plugins/dpdk/device/node.c | 44 +++++++++++- src/vnet/unix/pcap.h | 28 ++++---- 5 files changed, 167 insertions(+), 81 deletions(-) diff --git a/src/plugins/dpdk/device/cli.c b/src/plugins/dpdk/device/cli.c index 08bf0c94b53..151a6f4e9c8 100644 --- a/src/plugins/dpdk/device/cli.c +++ b/src/plugins/dpdk/device/cli.c @@ -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 ] [intfc |any] [file ] [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 ] [intfc |any] [file ] [status]", + .function = pcap_rx_trace_command_fn, }; /* *INDENT-ON* */ diff --git a/src/plugins/dpdk/device/device.c b/src/plugins/dpdk/device/device.c index 0ac798fa704..5409fe4f50e 100644 --- a/src/plugins/dpdk/device/device.c +++ b/src/plugins/dpdk/device/device.c @@ -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--; } diff --git a/src/plugins/dpdk/device/dpdk.h b/src/plugins/dpdk/device/dpdk.h index eed1126da74..c60312e804b 100644 --- a/src/plugins/dpdk/device/dpdk.h +++ b/src/plugins/dpdk/device/dpdk.h @@ -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; diff --git a/src/plugins/dpdk/device/node.c b/src/plugins/dpdk/device/node.c index a1acc1f0d1e..daccf733372 100644 --- a/src/plugins/dpdk/device/node.c +++ b/src/plugins/dpdk/device/node.c @@ -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, diff --git a/src/vnet/unix/pcap.h b/src/vnet/unix/pcap.h index 7d55db37979..1ab1531cfa3 100644 --- a/src/vnet/unix/pcap.h +++ b/src/vnet/unix/pcap.h @@ -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 */ -- cgit 1.2.3-korg