From fb8f51697c748d28d4b542554a96a83ab74f6678 Mon Sep 17 00:00:00 2001 From: Hadi Rayan Al-Sandid Date: Tue, 26 Nov 2024 15:58:40 +0100 Subject: [PATCH] bpf_trace_filter: allow pcap filtering without classifier Type: improvement Change-Id: I7ca860dbee0d0a24b7f00943142d8c878ed90e80 Signed-off-by: Hadi Rayan Al-Sandid --- src/vnet/classify/pcap_classify.h | 2 +- src/vnet/interface_cli.c | 21 ++++++----- src/vnet/vnet.h | 2 +- test/test_bpf_trace_filter.py | 60 +++++++++++++++++++++++++++++++ test/test_pcap.py | 17 +++++++++ 5 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/vnet/classify/pcap_classify.h b/src/vnet/classify/pcap_classify.h index a4ebcd1241c..c23267fd504 100644 --- a/src/vnet/classify/pcap_classify.h +++ b/src/vnet/classify/pcap_classify.h @@ -46,7 +46,7 @@ vnet_is_packet_pcaped (vnet_pcap_t *pp, vlib_buffer_t *b, u32 sw_if_index) if (pcap_error_index != (vlib_error_t) ~0 && pcap_error_index != b->error) return 0; /* wrong error */ - if (filter_classify_table_index != ~0 && + if (pp->pcap_filter_enable && pp->current_filter_function (b, filter_classify_table_index, 0 /* full classify */) != 1) return 0; /* not matching the filter, skip */ diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index c56eb9777cf..cc214c10f6b 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -2041,6 +2041,12 @@ format_vnet_pcap (u8 * s, va_list * args) s = format (s, "drop"); printed = 1; } + + if (printed && pp->pcap_filter_enable) + { + s = format (s, "with filter"); + printed = 1; + } return s; } s = format (s, "unknown type %d!", type); @@ -2092,12 +2098,6 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) && (pm->n_packets_to_capture != a->packets_to_capture)) return VNET_API_ERROR_INVALID_VALUE_2; - /* Classify filter specified, but no classify filter configured */ - if ((a->rx_enable + a->tx_enable + a->drop_enable) && a->filter && - (!cm->classify_table_index_by_sw_if_index || - cm->classify_table_index_by_sw_if_index[0] == ~0)) - return VNET_API_ERROR_NO_SUCH_LABEL; - if (a->rx_enable + a->tx_enable + a->drop_enable) { void *save_pcap_data; @@ -2151,11 +2151,13 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) } pm->n_packets_to_capture = a->packets_to_capture; pp->pcap_sw_if_index = a->sw_if_index; - if (a->filter) + if (a->filter && cm->classify_table_index_by_sw_if_index && + cm->classify_table_index_by_sw_if_index[0] != ~0) pp->filter_classify_table_index = cm->classify_table_index_by_sw_if_index[0]; else pp->filter_classify_table_index = ~0; + pp->pcap_filter_enable = a->filter; pp->pcap_error_index = a->drop_err; pp->pcap_rx_enable = a->rx_enable; pp->pcap_tx_enable = a->tx_enable; @@ -2164,6 +2166,7 @@ vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a) } else { + pp->pcap_filter_enable = 0; pp->pcap_rx_enable = 0; pp->pcap_tx_enable = 0; pp->pcap_drop_enable = 0; @@ -2312,10 +2315,6 @@ pcap_trace_command_fn (vlib_main_t * vm, 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...'"); - default: vlib_cli_output (vm, "WARNING: trace configure returned %d", rv); break; diff --git a/src/vnet/vnet.h b/src/vnet/vnet.h index 54988aec667..6e436cc3952 100644 --- a/src/vnet/vnet.h +++ b/src/vnet/vnet.h @@ -66,7 +66,7 @@ typedef struct u8 pcap_tx_enable; /* Trace drop pkts */ u8 pcap_drop_enable; - u8 pad1; + u8 pcap_filter_enable; u32 max_bytes_per_pkt; u32 pcap_sw_if_index; pcap_main_t pcap_main; diff --git a/test/test_bpf_trace_filter.py b/test/test_bpf_trace_filter.py index 6958caa6b37..d90088a5412 100644 --- a/test/test_bpf_trace_filter.py +++ b/test/test_bpf_trace_filter.py @@ -1,5 +1,7 @@ from framework import VppTestCase from asfframework import VppTestRunner +from vpp_papi_provider import CliFailedCommandError +import os import unittest from config import config from scapy.layers.l2 import Ether @@ -77,6 +79,17 @@ class TestBpfTraceFilter(VppTestCase): "Unexpected packets in the trace buffer", ) + # verify that bpf trace filter has been selected for pcap + self.vapi.cli("set pcap filter function bpf_trace_filter") + self.vapi.cli("pcap trace rx tx max 1000 intfc any filter") + + # verify that packets are filtered in not captured in pcap + self.pg0.add_stream(packets) + self.pg_start() + + with self.assertRaises(CliFailedCommandError): + self.vapi.cli("pcap trace rx tx off") + reply = self.vapi.cli("show bpf trace filter") self.assertIn("(000)", reply, "Unexpected bpf filter dump") @@ -103,6 +116,29 @@ class TestBpfTraceFilter(VppTestCase): "Unexpected packets in the trace buffer", ) + # verify that bpf trace filter has been selected for pcap + self.vapi.pcap_set_filter_function(filter_function_name="bpf_trace_filter") + reply = self.vapi.cli("show pcap filter function") + self.assertIn( + "(*) name:bpf_trace_filter", + reply, + "BPF Trace filter is not selected for Pcap", + ) + + # verify that packets are filtered in not captured in pcap + self.vapi.pcap_trace_on( + capture_rx=True, + capture_tx=True, + max_packets=1000, + filter=True, + sw_if_index=0, + filename="bpf_trace.pcap", + ) + self.pg0.add_stream(packets) + self.pg_start() + with self.vapi.assert_negative_api_retval(): + self.vapi.pcap_trace_off() + def test_bpf_trace_filter_vapi_v2(self): """BPF Trace filter test [VAPI v2]""" self.vapi.bpf_trace_filter_set_v2(filter="tcp or dst port 5678") @@ -131,6 +167,30 @@ class TestBpfTraceFilter(VppTestCase): "Unexpected packets in the trace buffer", ) + # verify that bpf trace filter has been selected for pcap + self.vapi.pcap_set_filter_function(filter_function_name="bpf_trace_filter") + reply = self.vapi.cli("show pcap filter function") + self.assertIn( + "(*) name:bpf_trace_filter", + reply, + "BPF Trace filter is not selected for Pcap", + ) + + # verify that packets are captured in pcap with filter + self.vapi.pcap_trace_on( + capture_rx=True, + capture_tx=True, + max_packets=1000, + filter=True, + sw_if_index=0, + filename="bpf_trace.pcap", + ) + self.pg0.add_stream(packets) + self.pg_start() + self.vapi.pcap_trace_off() + self.assertTrue(os.path.exists("/tmp/bpf_trace.pcap")) + os.remove("/tmp/bpf_trace.pcap") + if __name__ == "__main__": unittest.main(testRunner=VppTestRunner) diff --git a/test/test_pcap.py b/test/test_pcap.py index 1169dcccfc1..94418081ace 100644 --- a/test/test_pcap.py +++ b/test/test_pcap.py @@ -75,11 +75,13 @@ class TestPcap(VppTestCase): "pa en", "pcap dispatch trace off", "pcap trace rx tx max 1000 intfc any", + "pcap trace status", "pa en", "pcap trace status", "pcap trace rx tx off", "classify filter pcap mask l3 ip4 src match l3 ip4 src 11.22.33.44", "pcap trace rx tx max 1000 intfc any file filt.pcap filter", + "pcap trace status", "show cla t verbose 2", "show cla t verbose", "show cla t", @@ -123,6 +125,21 @@ class TestPcap(VppTestCase): self.pg_send(self.pg0, pkt * 10) self.vapi.pcap_trace_off() + # Launching trace with filter & no classifier table specified + # should result in no packet capture + self.vapi.pcap_trace_on( + capture_rx=True, + capture_tx=True, + max_packets=1000, + filter=True, + sw_if_index=0, + filename="trace_any_invalid_filter.pcap", + ) + self.pg_send(self.pg0, pkt * 10) + with self.vapi.assert_negative_api_retval(): + self.vapi.pcap_trace_off() + self.assertFalse(os.path.exists("/tmp/trace_any_invalid_filter.pcap")) + self.vapi.cli( f"classify filter pcap mask l3 ip4 src match l3 ip4 src {self.pg0.local_ip4}" )