aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2020-06-10 17:07:32 -0400
committerDave Barach <openvpp@barachs.net>2020-06-16 11:50:17 +0000
commit4330c46abb78882fc453b1b682ac4f12a22b5e68 (patch)
tree408fee677cb70bb723001c60c6b14b53e12fd775
parentcf9bb22a9483b97b00b7dcacc35b37ae0fcaefbe (diff)
interface: add minimal vpp pkt trace for error-drop
Provide a minimal trace [ip4/ip6 src/dst address] for dropped pkts when the user specifies "trace add error-drop XXXX", but does not trace pkts from the original input node. This is a wireshark dissector problem. Packets thrown at error-drop may be well-formed, or not. VPP must not crash, no matter what. The minimal trace capture and decode could be enhanced. Anyone interested in doing that must consider all of the corner-cases involved. This version should be at least somewhat useful. Note that "pcap trace drop ..." - and the packet generator - seem like the right tools to use when researching more complex issues. Type: improvement Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: I961ca133980ffa2a1e5707879a443b21442ed894
-rw-r--r--src/vnet/interface_cli.c2
-rw-r--r--src/vnet/interface_output.c131
2 files changed, 125 insertions, 8 deletions
diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c
index 2e5714c3c0f..569e2eb6c54 100644
--- a/src/vnet/interface_cli.c
+++ b/src/vnet/interface_cli.c
@@ -2046,7 +2046,7 @@ pcap_trace_command_fn (vlib_main_t * vm,
int drop_enable = 0;
int status = 0;
int filter = 0;
- u32 sw_if_index = ~0;
+ u32 sw_if_index = 0; /* default: any interface */
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
diff --git a/src/vnet/interface_output.c b/src/vnet/interface_output.c
index f9490f34f6a..cb13f5361aa 100644
--- a/src/vnet/interface_output.c
+++ b/src/vnet/interface_output.c
@@ -39,6 +39,7 @@
#include <vnet/vnet.h>
#include <vnet/ip/icmp46_packet.h>
+#include <vnet/ethernet/packet.h>
#include <vnet/ip/ip4.h>
#include <vnet/ip/ip6.h>
#include <vnet/udp/udp_packet.h>
@@ -603,9 +604,13 @@ VLIB_NODE_FN (vnet_per_buffer_interface_output_node) (vlib_main_t * vm,
typedef struct vnet_error_trace_t_
{
u32 sw_if_index;
+ i8 details_valid;
+ u8 is_ip6;
+ u8 pad[2];
+ u16 mactype;
+ ip46_address_t src, dst;
} vnet_error_trace_t;
-
static u8 *
format_vnet_error_trace (u8 * s, va_list * va)
{
@@ -613,9 +618,29 @@ format_vnet_error_trace (u8 * s, va_list * va)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
vnet_error_trace_t *t = va_arg (*va, vnet_error_trace_t *);
- s = format (s, "rx:%U", format_vnet_sw_if_index_name,
- vnet_get_main (), t->sw_if_index);
-
+ /* Normal, non-catchup trace */
+ if (t->details_valid == 0)
+ {
+ s = format (s, "rx:%U", format_vnet_sw_if_index_name,
+ vnet_get_main (), t->sw_if_index);
+ }
+ else if (t->details_valid == 1)
+ {
+ /* The trace capture code didn't understant the mactype */
+ s = format (s, "mactype 0x%4x (not decoded)", t->mactype);
+ }
+ else if (t->details_valid == 2)
+ {
+ /* Dump the src/dst addresses */
+ if (t->is_ip6 == 0)
+ s = format (s, "IP4: %U -> %U",
+ format_ip4_address, &t->src.ip4,
+ format_ip4_address, &t->dst.ip4);
+ else
+ s = format (s, "IP6: %U -> %U",
+ format_ip6_address, &t->src.ip6,
+ format_ip6_address, &t->dst.ip6);
+ }
return s;
}
@@ -646,13 +671,17 @@ interface_trace_buffers (vlib_main_t * vm,
if (b0->flags & VLIB_BUFFER_IS_TRACED)
{
- t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
+ t0 = vlib_add_trace (vm, node, b0,
+ STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ t0->details_valid = 0;
}
if (b1->flags & VLIB_BUFFER_IS_TRACED)
{
- t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
+ t1 = vlib_add_trace (vm, node, b1,
+ STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+ t1->details_valid = 0;
}
buffers += 2;
n_left -= 2;
@@ -670,8 +699,10 @@ interface_trace_buffers (vlib_main_t * vm,
if (b0->flags & VLIB_BUFFER_IS_TRACED)
{
- t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
+ t0 = vlib_add_trace (vm, node, b0,
+ STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ t0->details_valid = 0;
}
buffers += 1;
n_left -= 1;
@@ -685,6 +716,56 @@ typedef enum
VNET_ERROR_N_DISPOSITION,
} vnet_error_disposition_t;
+static void
+drop_catchup_trace (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_buffer_t * b)
+{
+ /* Can we safely rewind the buffer? If not, fagedaboudit */
+ if (b->flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
+ {
+ vnet_error_trace_t *t;
+ ip4_header_t *ip4;
+ ip6_header_t *ip6;
+ ethernet_header_t *eh;
+ i16 delta;
+
+ t = vlib_add_trace (vm, node, b, sizeof (*t));
+ delta = vnet_buffer (b)->l2_hdr_offset - b->current_data;
+ vlib_buffer_advance (b, delta);
+
+ eh = vlib_buffer_get_current (b);
+ /* Save mactype */
+ t->mactype = clib_net_to_host_u16 (eh->type);
+ t->details_valid = 1;
+ switch (t->mactype)
+ {
+ case ETHERNET_TYPE_IP4:
+ ip4 = (void *) (eh + 1);
+ t->details_valid = 2;
+ t->is_ip6 = 0;
+ t->src.ip4.as_u32 = ip4->src_address.as_u32;
+ t->dst.ip4.as_u32 = ip4->dst_address.as_u32;
+ break;
+
+ case ETHERNET_TYPE_IP6:
+ ip6 = (void *) (eh + 1);
+ t->details_valid = 2;
+ t->is_ip6 = 1;
+ clib_memcpy_fast (t->src.as_u8, ip6->src_address.as_u8,
+ sizeof (ip6_address_t));
+ clib_memcpy_fast (t->dst.as_u8, ip6->dst_address.as_u8,
+ sizeof (ip6_address_t));
+ break;
+
+ default:
+ /* Dunno, do nothing, leave details_valid alone */
+ break;
+ }
+ /* Restore current data (probably unnecessary) */
+ vlib_buffer_advance (b, -delta);
+ }
+}
+
static_always_inline uword
interface_drop_punt (vlib_main_t * vm,
vlib_node_runtime_t * node,
@@ -696,6 +777,7 @@ interface_drop_punt (vlib_main_t * vm,
u32 sw_if_indices[VLIB_FRAME_SIZE];
vlib_simple_counter_main_t *cm;
u16 nexts[VLIB_FRAME_SIZE];
+ u32 n_trace;
vnet_main_t *vnm;
vnm = vnet_get_main ();
@@ -707,6 +789,39 @@ interface_drop_punt (vlib_main_t * vm,
vlib_get_buffers (vm, from, bufs, n_left);
+ /* "trace add error-drop NNN?" */
+ if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, node))))
+ {
+ /* If pkts aren't otherwise traced... */
+ if ((node->flags & VLIB_NODE_FLAG_TRACE) == 0)
+ {
+ /* Trace them from here */
+ 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--;
+ n_left--;
+ b++;
+ }
+ }
+
+ vlib_set_trace_count (vm, node, n_trace);
+ b = bufs;
+ n_left = frame->n_vectors;
+ }
+
if (node->flags & VLIB_NODE_FLAG_TRACE)
interface_trace_buffers (vm, node, frame);
@@ -947,6 +1062,7 @@ VLIB_REGISTER_NODE (interface_drop) = {
.name = "error-drop",
.vector_size = sizeof (u32),
.format_trace = format_vnet_error_trace,
+ .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
.n_next_nodes = 1,
.next_nodes = {
[0] = "drop",
@@ -959,6 +1075,7 @@ VLIB_REGISTER_NODE (interface_punt) = {
.name = "error-punt",
.vector_size = sizeof (u32),
.format_trace = format_vnet_error_trace,
+ .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
.n_next_nodes = 1,
.next_nodes = {
[0] = "punt",