From 33909777c63712ca397165cd92e7cc62208eb5c8 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Mon, 23 Sep 2019 10:27:27 -0400 Subject: misc: unify pcap rx / tx / drop trace Use a single vnet_pcap_t in vlib_global_main, specifically to support unified tracing Update sphinx docs, doxygen tags Type: refactor Ticket: VPP-1776 Signed-off-by: Dave Barach Change-Id: Id15d41a596712968c0714cef1bd2cd5bc9cbdd55 --- src/vnet/ethernet/node.c | 16 ++-- src/vnet/interface.h | 16 ++-- src/vnet/interface_cli.c | 185 ++++++++++++++++++++++++++++---------------- src/vnet/interface_output.c | 165 ++++----------------------------------- 4 files changed, 152 insertions(+), 230 deletions(-) (limited to 'src/vnet') diff --git a/src/vnet/ethernet/node.c b/src/vnet/ethernet/node.c index fb706551719..ee14e40d881 100755 --- a/src/vnet/ethernet/node.c +++ b/src/vnet/ethernet/node.c @@ -998,10 +998,11 @@ ethernet_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node, } /* rx pcap capture if enabled */ - if (PREDICT_FALSE (vlib_global_main.pcap[VLIB_RX].pcap_enable)) + if (PREDICT_FALSE (vlib_global_main.pcap.pcap_rx_enable)) { u32 bi0; vnet_main_t *vnm = vnet_get_main (); + vnet_pcap_t *pp = &vlib_global_main.pcap; from = vlib_frame_vector_args (from_frame); n_left = from_frame->n_vectors; @@ -1020,17 +1021,16 @@ ethernet_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node, (b0, vnm->classify_filter_table_indices[0], 0 /* full classify */ ); if (classify_filter_result) - pcap_add_buffer (&vlib_global_main.pcap[VLIB_RX].pcap_main, - vm, bi0, 512); + pcap_add_buffer (&pp->pcap_main, vm, bi0, + pp->max_bytes_per_pkt); continue; } - if (vlib_global_main.pcap[VLIB_RX].pcap_sw_if_index == 0 || - vlib_global_main.pcap[VLIB_RX].pcap_sw_if_index - == vnet_buffer (b0)->sw_if_index[VLIB_RX]) + if (pp->pcap_sw_if_index == 0 || + pp->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX]) { - pcap_add_buffer (&vlib_global_main.pcap[VLIB_RX].pcap_main, vm, - bi0, 512); + pcap_add_buffer (&pp->pcap_main, vm, bi0, + pp->max_bytes_per_pkt); } } } diff --git a/src/vnet/interface.h b/src/vnet/interface.h index 0c273c6c7d2..00ed1f03151 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -843,12 +843,11 @@ typedef struct vnet_hw_interface_nodes_t *deleted_hw_interface_nodes; - /* pcap drop tracing */ - int drop_pcap_enable; - pcap_main_t pcap_main; - u8 *pcap_filename; - u32 pcap_sw_if_index; - u32 pcap_pkts_to_capture; + /* + * pcap drop tracing + * Only the drop filter hash lives here. See ../src/vlib/main.h for + * the rest of the variables. + */ uword *pcap_drop_filter_hash; /* Buffer metadata format helper functions */ @@ -899,7 +898,10 @@ typedef struct int enable; int status; u32 packets_to_capture; - vlib_rx_or_tx_t rxtx; + u32 max_bytes_per_pkt; + u8 rx_enable; + u8 tx_enable; + u8 drop_enable; u32 sw_if_index; int filter; } vnet_pcap_dispatch_trace_args_t; diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index 3164f7a31f2..e6b251da17f 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -1695,52 +1695,94 @@ VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = { }; /* *INDENT-ON* */ +static u8 * +format_vnet_pcap (u8 * s, va_list * args) +{ + vnet_pcap_t *pp = va_arg (*args, vnet_pcap_t *); + int type = va_arg (*args, int); + int printed = 0; + + if (type == 0) + { + if (pp->pcap_rx_enable) + { + s = format (s, "rx"); + printed = 1; + } + if (pp->pcap_tx_enable) + { + if (printed) + s = format (s, " and "); + s = format (s, "tx"); + printed = 1; + } + if (pp->pcap_drop_enable) + { + if (printed) + s = format (s, " and "); + s = format (s, "drop"); + printed = 1; + } + return s; + } + s = format (s, "unknown type %d!", type); + return s; +} + + int vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) { vlib_main_t *vm = vlib_get_main (); vnet_main_t *vnm = vnet_get_main (); - vlib_rx_or_tx_t rxtx = a->rxtx; - vnet_pcap_t *pp = &vm->pcap[rxtx]; + vnet_pcap_t *pp = &vm->pcap; pcap_main_t *pm = &pp->pcap_main; if (a->status) { - if (pp->pcap_enable) + if (pp->pcap_rx_enable || pp->pcap_tx_enable || pp->pcap_drop_enable) { vlib_cli_output - (vm, "pcap %s dispatch capture enabled: %d of %d pkts...", - (rxtx == VLIB_RX) ? "rx" : "tx", + (vm, "pcap %U dispatch capture enabled: %d of %d pkts...", + format_vnet_pcap, pp, 0 /* print type */ , pm->n_packets_captured, pm->n_packets_to_capture); vlib_cli_output (vm, "capture to file %s", pm->file_name); } else - vlib_cli_output (vm, "pcap %s dispatch capture disabled", - (rxtx == VLIB_RX) ? "rx" : "tx"); + vlib_cli_output (vm, "pcap dispatch capture disabled"); + return 0; } /* Consistency checks */ /* Enable w/ capture already enabled not allowed */ - if (pp->pcap_enable && a->enable) + if ((pp->pcap_rx_enable + pp->pcap_tx_enable + pp->pcap_drop_enable) + && (a->rx_enable + a->tx_enable + a->drop_enable)) return VNET_API_ERROR_INVALID_VALUE; /* Disable capture with capture already disabled, not interesting */ - if (pp->pcap_enable == 0 && a->enable == 0) + if (((pp->pcap_rx_enable + pp->pcap_tx_enable + pp->pcap_drop_enable) == 0) + && ((a->rx_enable + a->tx_enable + a->drop_enable == 0))) return VNET_API_ERROR_VALUE_EXIST; /* Change number of packets to capture while capturing */ - if (pp->pcap_enable && a->enable + if ((pp->pcap_rx_enable + pp->pcap_tx_enable + pp->pcap_drop_enable) + && (a->rx_enable + a->tx_enable + a->drop_enable) && (pm->n_packets_to_capture != a->packets_to_capture)) return VNET_API_ERROR_INVALID_VALUE_2; - if (a->enable && a->filter + /* Classify filter specified, but no classify filter configured */ + if ((a->rx_enable + a->tx_enable + a->drop_enable) && a->filter && (vec_len (vnm->classify_filter_table_indices) == 0)) return VNET_API_ERROR_NO_SUCH_LABEL; - if (a->enable) + if (a->rx_enable + a->tx_enable + a->drop_enable) { + /* Sanity check max bytes per pkt */ + if (a->max_bytes_per_pkt < 32 || a->max_bytes_per_pkt > 9000) + return VNET_API_ERROR_INVALID_MEMORY_SIZE; + /* Clean up from previous run, if any */ vec_free (pm->file_name); vec_free (pm->pcap_data); @@ -1751,8 +1793,18 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) clib_spinlock_init (&(pm->lock)); if (a->filename == 0) - a->filename = format (0, "/tmp/%s.pcap%c", - (rxtx == VLIB_RX) ? "rx" : "tx", 0); + { + u8 *stem = 0; + + if (a->rx_enable) + stem = format (stem, "rx"); + if (a->tx_enable) + stem = format (stem, "tx"); + if (a->drop_enable) + stem = format (stem, "drop"); + a->filename = format (0, "/tmp/%s.pcap%c", stem, 0); + vec_free (stem); + } pm->file_name = (char *) a->filename; pm->n_packets_captured = 0; @@ -1764,11 +1816,16 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) vnm->classify_filter_table_indices[0]; else pp->filter_classify_table_index = ~0; - pp->pcap_enable = 1; + pp->pcap_rx_enable = a->rx_enable; + pp->pcap_tx_enable = a->tx_enable; + pp->pcap_drop_enable = a->drop_enable; + pp->max_bytes_per_pkt = a->max_bytes_per_pkt; } else { - pp->pcap_enable = 0; + pp->pcap_rx_enable = 0; + pp->pcap_tx_enable = 0; + pp->pcap_drop_enable = 0; if (pm->n_packets_captured) { clib_error_t *error; @@ -1794,17 +1851,19 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) } static clib_error_t * -pcap_trace_command_internal (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd, vlib_rx_or_tx_t rxtx) +pcap_trace_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; vnet_pcap_dispatch_trace_args_t _a, *a = &_a; vnet_main_t *vnm = vnet_get_main (); u8 *filename = 0; u32 max = 1000; + u32 max_bytes_per_pkt = 512; int rv; - int enable = 0; + int rx_enable = 0; + int tx_enable = 0; + int drop_enable = 0; int status = 0; int filter = 0; u32 sw_if_index = 0; @@ -1815,13 +1874,16 @@ pcap_trace_command_internal (vlib_main_t * vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat (line_input, "on %=", &enable, 1)) - ; - else if (unformat (line_input, "enable %=", &enable, 1)) - ; - else if (unformat (line_input, "off %=", &enable, 0)) - ; - else if (unformat (line_input, "disable %=", &enable, 0)) + if (unformat (line_input, "rx")) + rx_enable = 1; + else if (unformat (line_input, "tx")) + tx_enable = 1; + else if (unformat (line_input, "drop")) + drop_enable = 1; + else if (unformat (line_input, "off")) + rx_enable = tx_enable = drop_enable = 0; + else if (unformat (line_input, "max-bytes-per-pkt %u", + &max_bytes_per_pkt)) ; else if (unformat (line_input, "max %d", &max)) ; @@ -1850,12 +1912,14 @@ pcap_trace_command_internal (vlib_main_t * vm, /* no need for memset (a, 0, sizeof (*a)), set all fields here. */ a->filename = filename; - a->enable = enable; + a->rx_enable = rx_enable; + a->tx_enable = tx_enable; + a->drop_enable = drop_enable; a->status = status; a->packets_to_capture = max; - a->rxtx = rxtx; a->sw_if_index = sw_if_index; a->filter = filter; + a->max_bytes_per_pkt = max_bytes_per_pkt; rv = vnet_pcap_dispatch_trace_configure (a); @@ -1880,6 +1944,10 @@ pcap_trace_command_internal (vlib_main_t * vm, case VNET_API_ERROR_NO_SUCH_ENTRY: return clib_error_return (0, "No packets captured..."); + case VNET_API_ERROR_INVALID_MEMORY_SIZE: + return clib_error_return (0, + "Max bytes per pkt must be > 32, < 9000..."); + case VNET_API_ERROR_NO_SUCH_LABEL: return clib_error_return (0, "No classify filter configured, see 'classify filter...'"); @@ -1891,30 +1959,20 @@ pcap_trace_command_internal (vlib_main_t * vm, return 0; } -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. Note that both "pcap rx trace" and - * "pcap tx trace" are implemented. The command syntax is identical, - * simply substitute rx for tx as needed. + * the status of packet capture. * * This command has the following optional parameters: * - * - on|off - Used to start or stop a packet capture. + * + * - rx - Capture received packets + * + * - tx - Capture transmitted packets + * + * - drop - Capture dropped packets + * + * - off - Stop capturing packets, write results to the specified file * * - max - Depth of local buffer. Once 'nn' number * of packets have been received, buffer is flushed to file. Once another @@ -1922,7 +1980,10 @@ pcap_tx_trace_command_fn (vlib_main_t * vm, * to file, overwriting previous write. If not entered, value defaults * to 100. Can only be updated if packet capture is off. * - * - intfc |any - Used to specify a given interface, + * - max-bytes-per-pkt - Maximum number of bytes to capture + * for each packet. Must be >= 32, <= 9000. + * + * - intfc |any - Used to specify a given interface, * or use 'any' to run packet capture on all interfaces. * 'any' is the default if not provided. Settings from a previous * packet capture are preserved, so 'any' can be used to reset @@ -1931,8 +1992,9 @@ pcap_tx_trace_command_fn (vlib_main_t * vm, * - file - Used to specify the output filename. The file will * be placed in the '/tmp' directory, so only the filename is * supported. Directory should not be entered. If file already exists, file - * will be overwritten. If no filename is provided, '/tmp/vpe.pcap' - * will be used. Can only be updated if packet capture is off. + * will be overwritten. If no filename is provided, the file will be + * named "/tmp/rx.pcap", "/tmp/tx.pcap", "/tmp/rxandtx.pcap", etc. + * Can only be updated if packet capture is off. * * - status - Displays the current status and configured attributes * associated with a packet capture. If packet capture is in progress, @@ -1942,21 +2004,20 @@ pcap_tx_trace_command_fn (vlib_main_t * vm, * * @cliexpar * Example of how to display the status of a tx packet capture when off: - * @cliexstart{pcap tx trace status} + * @cliexstart{pcap trace status} * max is 100, for any interface to file /tmp/vpe.pcap * pcap tx capture is off... * @cliexend * Example of how to start a tx packet capture: - * @cliexstart{pcap tx trace on max 35 intfc GigabitEthernet0/8/0 file vppTest.pcap} - * pcap tx capture on... + * @cliexstart{pcap trace tx max 35 intfc GigabitEthernet0/8/0 file vppTest.pcap} * @cliexend * Example of how to display the status of a tx packet capture in progress: - * @cliexstart{pcap tx trace status} + * @cliexstart{pcap trace status} * max is 35, for interface GigabitEthernet0/8/0 to file /tmp/vppTest.pcap * pcap tx capture is on: 20 of 35 pkts... * @cliexend * Example of how to stop a tx packet capture: - * @cliexstart{vppctl pcap tx trace off} + * @cliexstart{pcap trace off} * captured 21 pkts... * saved to /tmp/vppTest.pcap... * @cliexend @@ -1964,16 +2025,10 @@ pcap_tx_trace_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ 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_tx_trace_command_fn, -}; -VLIB_CLI_COMMAND (pcap_rx_trace_command, static) = { - .path = "pcap rx trace", + .path = "pcap trace", .short_help = - "pcap rx trace [on|off] [max ] [intfc |any] [file ] [status]", - .function = pcap_rx_trace_command_fn, + "pcap trace rx tx drop off [max ] [intfc |any] [file ] [status] [max-bytes-per-pkt ]", + .function = pcap_trace_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/interface_output.c b/src/vnet/interface_output.c index 721236a777f..8eb2e67b1bd 100644 --- a/src/vnet/interface_output.c +++ b/src/vnet/interface_output.c @@ -802,8 +802,10 @@ static_always_inline void vnet_interface_pcap_tx_trace { u32 n_left_from, *from; u32 sw_if_index; + vnet_main_t *vnm; + vnet_pcap_t *pp = &vlib_global_main.pcap; - if (PREDICT_TRUE (vlib_global_main.pcap[VLIB_TX].pcap_enable == 0)) + if (PREDICT_TRUE (pp->pcap_tx_enable == 0)) return; if (sw_if_index_from_buffer == 0) @@ -814,7 +816,7 @@ static_always_inline void vnet_interface_pcap_tx_trace else sw_if_index = ~0; - vnet_main_t *vnm = vnet_get_main (); + vnm = vnet_get_main (); n_left_from = frame->n_vectors; from = vlib_frame_vector_args (frame); @@ -833,18 +835,15 @@ static_always_inline void vnet_interface_pcap_tx_trace (b0, vnm->classify_filter_table_indices[0], 0 /* full classify */ ); if (classify_filter_result) - pcap_add_buffer (&vlib_global_main.pcap[VLIB_TX].pcap_main, vm, - bi0, 512); + pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt); continue; } if (sw_if_index_from_buffer) sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - if (vlib_global_main.pcap[VLIB_TX].pcap_sw_if_index == 0 || - vlib_global_main.pcap[VLIB_TX].pcap_sw_if_index == sw_if_index) - pcap_add_buffer (&vlib_global_main.pcap[VLIB_TX].pcap_main, vm, bi0, - 512); + if (pp->pcap_sw_if_index == 0 || pp->pcap_sw_if_index == sw_if_index) + pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt); } } @@ -1169,7 +1168,8 @@ interface_drop_punt (vlib_main_t * vm, static inline void pcap_drop_trace (vlib_main_t * vm, - vnet_interface_main_t * im, vlib_frame_t * f) + vnet_interface_main_t * im, + vnet_pcap_t * pp, vlib_frame_t * f) { u32 *from; u32 n_left = f->n_vectors; @@ -1199,8 +1199,8 @@ pcap_drop_trace (vlib_main_t * vm, continue; /* Trace all drops, or drops received on a specific interface */ - if (im->pcap_sw_if_index == 0 || - im->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX]) + if (pp->pcap_sw_if_index == 0 || + pp->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX]) { save_current_data = b0->current_data; save_current_length = b0->current_length; @@ -1222,7 +1222,7 @@ pcap_drop_trace (vlib_main_t * vm, else if (b0->current_data > 0) vlib_buffer_advance (b0, (word) - b0->current_data); - pcap_add_buffer (&im->pcap_main, vm, bi0, 512); + pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt); b0->current_data = save_current_data; b0->current_length = save_current_length; @@ -1251,9 +1251,10 @@ VLIB_NODE_FN (interface_drop) (vlib_main_t * vm, vlib_frame_t * frame) { vnet_interface_main_t *im = &vnet_get_main ()->interface_main; + vnet_pcap_t *pp = &vlib_global_main.pcap; - if (PREDICT_FALSE (im->drop_pcap_enable)) - pcap_drop_trace (vm, im, frame); + if (PREDICT_FALSE (pp->pcap_drop_enable)) + pcap_drop_trace (vm, im, pp, frame); return interface_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP); } @@ -1416,142 +1417,6 @@ vnet_set_interface_output_node (vnet_main_t * vnm, } #endif /* CLIB_MARCH_VARIANT */ -static clib_error_t * -pcap_drop_trace_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - vnet_interface_main_t *im = &vnm->interface_main; - u8 *filename; - u32 max; - int matched = 0; - clib_error_t *error = 0; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "on")) - { - if (im->drop_pcap_enable == 0) - { - if (im->pcap_filename == 0) - im->pcap_filename = format (0, "/tmp/drop.pcap%c", 0); - - clib_memset (&im->pcap_main, 0, sizeof (im->pcap_main)); - im->pcap_main.file_name = (char *) im->pcap_filename; - im->pcap_main.n_packets_to_capture = PCAP_DEF_PKT_TO_CAPTURE; - if (im->pcap_pkts_to_capture) - im->pcap_main.n_packets_to_capture = im->pcap_pkts_to_capture; - - im->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet; - im->drop_pcap_enable = 1; - matched = 1; - vlib_cli_output (vm, "pcap drop capture on..."); - } - else - { - vlib_cli_output (vm, "pcap drop capture already on..."); - } - matched = 1; - } - else if (unformat (input, "off")) - { - matched = 1; - - if (im->drop_pcap_enable) - { - vlib_cli_output (vm, "captured %d pkts...", - im->pcap_main.n_packets_captured); - if (im->pcap_main.n_packets_captured) - { - im->pcap_main.n_packets_to_capture = - im->pcap_main.n_packets_captured; - error = pcap_write (&im->pcap_main); - if (im->pcap_main.flags & PCAP_MAIN_INIT_DONE) - pcap_close (&im->pcap_main); - if (error) - clib_error_report (error); - else - vlib_cli_output (vm, "saved to %s...", im->pcap_filename); - } - } - else - { - vlib_cli_output (vm, "pcap drop capture already off..."); - } - - im->drop_pcap_enable = 0; - } - else if (unformat (input, "max %d", &max)) - { - im->pcap_pkts_to_capture = max; - matched = 1; - } - - else if (unformat (input, "intfc %U", - unformat_vnet_sw_interface, vnm, - &im->pcap_sw_if_index)) - matched = 1; - else if (unformat (input, "intfc any")) - { - im->pcap_sw_if_index = 0; - matched = 1; - } - else if (unformat (input, "file %s", &filename)) - { - u8 *chroot_filename; - /* Brain-police user path input */ - if (strstr ((char *) filename, "..") - || index ((char *) filename, '/')) - { - vlib_cli_output (vm, "illegal characters in filename '%s'", - filename); - continue; - } - - chroot_filename = format (0, "/tmp/%s%c", filename, 0); - vec_free (filename); - - if (im->pcap_filename) - vec_free (im->pcap_filename); - im->pcap_filename = chroot_filename; - im->pcap_main.file_name = (char *) im->pcap_filename; - matched = 1; - } - else if (unformat (input, "status")) - { - if (im->drop_pcap_enable == 0) - { - vlib_cli_output (vm, "pcap drop capture is off..."); - continue; - } - - vlib_cli_output (vm, "pcap drop capture: %d of %d pkts...", - im->pcap_main.n_packets_captured, - im->pcap_main.n_packets_to_capture); - matched = 1; - } - - else - break; - } - - if (matched == 0) - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - - return 0; -} - -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (pcap_trace_command, static) = { - .path = "pcap drop trace", - .short_help = - "pcap drop trace on off max intfc file status", - .function = pcap_drop_trace_command_fn, -}; -/* *INDENT-ON* */ - /* * fd.io coding-style-patch-verification: ON * -- cgit 1.2.3-korg