From: Benoît Ganne Date: Wed, 3 Mar 2021 16:37:25 +0000 (+0100) Subject: misc: add filter for specific error for pcap trace X-Git-Tag: v21.10-rc0~212 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F93%2F31493%2F10;p=vpp.git misc: add filter for specific error for pcap trace Type: feature Change-Id: I325257454df1cc22833fa6a1dedd4739d4d5a558 Signed-off-by: Benoît Ganne --- diff --git a/src/vlib/error.c b/src/vlib/error.c index 99664c618a9..1a84e7e6801 100644 --- a/src/vlib/error.c +++ b/src/vlib/error.c @@ -210,6 +210,37 @@ vlib_register_errors (vlib_main_t * vm, } } +uword +unformat_vlib_error (unformat_input_t *input, va_list *args) +{ + vlib_main_t *vm = va_arg (*args, vlib_main_t *); + const vlib_error_main_t *em = &vm->error_main; + vlib_error_t *error_index = va_arg (*args, vlib_error_t *); + const vlib_node_t *node; + char *error_name; + u32 node_index; + vlib_error_t i; + + if (!unformat (input, "%U.%s", unformat_vlib_node, vm, &node_index, + &error_name)) + return 0; + + node = vlib_get_node (vm, node_index); + for (i = 0; i < node->n_errors; i++) + { + vlib_error_t ei = node->error_heap_index + i; + if (strcmp (em->counters_heap[ei].name, error_name) == 0) + { + *error_index = ei; + vec_free (error_name); + return 1; + } + } + + vec_free (error_name); + return 0; +} + static char * sev2str (enum vl_counter_severity_e s) { diff --git a/src/vlib/error.h b/src/vlib/error.h index 11757e05f67..2bffc6b9367 100644 --- a/src/vlib/error.h +++ b/src/vlib/error.h @@ -40,6 +40,8 @@ #ifndef included_vlib_error_h #define included_vlib_error_h +#include + typedef u16 vlib_error_t; enum vl_counter_severity_e @@ -75,6 +77,8 @@ void vlib_register_errors (struct vlib_main_t *vm, u32 n_errors, char *error_strings[], vl_counter_t counters[]); +unformat_function_t unformat_vlib_error; + #endif /* included_vlib_error_h */ /* diff --git a/src/vnet/classify/pcap_classify.h b/src/vnet/classify/pcap_classify.h index 1f1c38fd6e6..e079816f62c 100644 --- a/src/vnet/classify/pcap_classify.h +++ b/src/vnet/classify/pcap_classify.h @@ -33,6 +33,7 @@ vnet_is_packet_pcaped (vnet_pcap_t *pp, vlib_buffer_t *b, u32 sw_if_index) { const u32 pcap_sw_if_index = pp->pcap_sw_if_index; const u32 filter_classify_table_index = pp->filter_classify_table_index; + const vlib_error_t pcap_error_index = pp->pcap_error_index; if (pcap_sw_if_index != 0) { @@ -42,6 +43,9 @@ vnet_is_packet_pcaped (vnet_pcap_t *pp, vlib_buffer_t *b, u32 sw_if_index) return 0; /* wrong interface, skip */ } + if (pcap_error_index != (vlib_error_t) ~0 && pcap_error_index != b->error) + return 0; /* wrong error */ + if (filter_classify_table_index != ~0 && vnet_is_packet_traced_inline (b, filter_classify_table_index, 0 /* full classify */) != 1) diff --git a/src/vnet/interface.h b/src/vnet/interface.h index b36d02c32bf..9d2f2a1c81d 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -1039,6 +1039,7 @@ typedef struct u8 free_data; u32 sw_if_index; int filter; + vlib_error_t drop_err; } vnet_pcap_dispatch_trace_args_t; int vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t *); diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index 9ade975937e..6dadbb8e8d3 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -2034,6 +2034,7 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) cm->classify_table_index_by_sw_if_index[0]; else pp->filter_classify_table_index = ~0; + pp->pcap_error_index = a->drop_err; pp->pcap_rx_enable = a->rx_enable; pp->pcap_tx_enable = a->tx_enable; pp->pcap_drop_enable = a->drop_enable; @@ -2045,6 +2046,7 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) pp->pcap_tx_enable = 0; pp->pcap_drop_enable = 0; pp->filter_classify_table_index = ~0; + pp->pcap_error_index = ~0; if (pm->n_packets_captured) { clib_error_t *error; @@ -2091,6 +2093,7 @@ pcap_trace_command_fn (vlib_main_t * vm, int filter = 0; int free_data = 0; u32 sw_if_index = 0; /* default: any interface */ + vlib_error_t drop_err = ~0; /* default: any error */ /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -2124,6 +2127,9 @@ pcap_trace_command_fn (vlib_main_t * vm, else if (unformat (line_input, "interface %U", unformat_vnet_sw_interface, vnm, &sw_if_index)) ; + else if (unformat (line_input, "error %U", unformat_vlib_error, vm, + &drop_err)) + ; else if (unformat (line_input, "preallocate-data %=", &preallocate_data, 1)) ; @@ -2155,6 +2161,7 @@ pcap_trace_command_fn (vlib_main_t * vm, a->sw_if_index = sw_if_index; a->filter = filter; a->max_bytes_per_pkt = max_bytes_per_pkt; + a->drop_err = drop_err; rv = vnet_pcap_dispatch_trace_configure (a); @@ -2235,6 +2242,9 @@ pcap_trace_command_fn (vlib_main_t * vm, * filter. The filter will only be executed if the per-interface or * any-interface tests fail. * + * - error . - filter packets based on a specific error. + * For example: error {ip4-udp-lookup}.{No listener for dst port} + * * - 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 @@ -2255,7 +2265,8 @@ pcap_trace_command_fn (vlib_main_t * vm, * pcap tx capture is off... * @cliexend * Example of how to start a tx packet capture: - * @cliexstart{pcap trace tx max 35 intfc GigabitEthernet0/8/0 file vppTest.pcap} + * @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 trace status} diff --git a/src/vnet/vnet.h b/src/vnet/vnet.h index 1deaff66375..24afe633af2 100644 --- a/src/vnet/vnet.h +++ b/src/vnet/vnet.h @@ -70,6 +70,7 @@ typedef struct u32 pcap_sw_if_index; pcap_main_t pcap_main; u32 filter_classify_table_index; + vlib_error_t pcap_error_index; } vnet_pcap_t; typedef struct vnet_main_t diff --git a/test/test_trace_filter.py b/test/test_trace_filter.py index 8869b3255d3..fd250ac17c7 100644 --- a/test/test_trace_filter.py +++ b/test/test_trace_filter.py @@ -174,7 +174,7 @@ class TestTracefilter(VppTestCase): "match l3 ip4 proto 17 l4 src_port 2345") self.cli( "pcap trace rx tx max 1000 intfc pg0 " - "file vpp_test_trace_filter.pcap filter") + "file vpp_test_trace_filter_test_pcap.pcap filter") # the packet we are trying to match p = list() for i in range(100): @@ -198,7 +198,7 @@ class TestTracefilter(VppTestCase): self.del_pcap_filters() # check captured pcap - pcap = rdpcap("/tmp/vpp_test_trace_filter.pcap") + pcap = rdpcap("/tmp/vpp_test_trace_filter_test_pcap.pcap") self.assertEqual(len(pcap), 9 + 17) p_ = str(p[5]) for i in range(9): @@ -207,6 +207,38 @@ class TestTracefilter(VppTestCase): for i in range(9, 9 + 17): self.assertEqual(str(pcap[i]), p_) + def test_pcap_drop(self): + """ Drop Packet Capture Filter Test """ + self.cli( + "pcap trace drop max 1000 " + "error {ip4-udp-lookup}.{No listener for dst port} " + "file vpp_test_trace_filter_test_pcap_drop.pcap") + # the packet we are trying to match + p = list() + for i in range(17): + # this packet should be forwarded + p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_hosts[0].ip4, + dst=self.pg1.remote_ip4) / + UDP(sport=2345, dport=1234) / Raw('\xa5' * 100))) + # this packet should be captured (no listener) + p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_hosts[0].ip4, + dst=self.pg0.local_ip4) / + UDP(sport=2345, dport=1234) / Raw('\xa5' * 100))) + # this packet will be blackholed but not captured + p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_hosts[0].ip4, dst="0.0.0.0") / + UDP(sport=2345, dport=1234) / Raw('\xa5' * 100))) + + self.send_and_expect(self.pg0, p, self.pg1, n_rx=17, trace=False) + + self.cli("pcap trace drop off") + + # check captured pcap + pcap = rdpcap("/tmp/vpp_test_trace_filter_test_pcap_drop.pcap") + self.assertEqual(len(pcap), 17) + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner)