bpf_trace_filter: plugin for BPF Trace Filtering 17/39017/16
authorMohammed Hawari <mohammed@hawari.fr>
Fri, 9 Jun 2023 14:50:56 +0000 (16:50 +0200)
committerBeno�t Ganne <bganne@cisco.com>
Fri, 30 Jun 2023 11:53:06 +0000 (11:53 +0000)
Change-Id: I342de0a375b783725aa2b621c1c70bc8bf646450
Signed-off-by: Mohammed Hawari <mohammed@hawari.fr>
Type: improvement

15 files changed:
MAINTAINERS
Makefile
docs/developer/plugins/bpf_trace_filter.rst [new symlink]
docs/developer/plugins/index.rst
docs/spelling_wordlist.txt
src/plugins/bpf_trace_filter/CMakeLists.txt [new file with mode: 0644]
src/plugins/bpf_trace_filter/FEATURE.yaml [new file with mode: 0644]
src/plugins/bpf_trace_filter/api.c [new file with mode: 0644]
src/plugins/bpf_trace_filter/bpf_trace_filter.api [new file with mode: 0644]
src/plugins/bpf_trace_filter/bpf_trace_filter.c [new file with mode: 0644]
src/plugins/bpf_trace_filter/bpf_trace_filter.h [new file with mode: 0644]
src/plugins/bpf_trace_filter/bpf_trace_filter.rst [new file with mode: 0644]
src/plugins/bpf_trace_filter/cli.c [new file with mode: 0644]
src/plugins/bpf_trace_filter/plugin.c [new file with mode: 0644]
src/vnet/classify/trace_classify.h

index 1117b6d..a07eb27 100644 (file)
@@ -806,6 +806,11 @@ I: prom
 M:     Florin Coras <fcoras@cisco.com>
 F:     src/plugins/prom
 
+Plugin - BPF Trace Filter
+I:      bpf_trace_filter
+M:      Mohammed Hawari <mohammed@hawari.fr>
+F:      src/plugins/bpf_trace_filter
+
 cJSON
 I:     cjson
 M:     Ole Troan <ot@cisco.com>
index 2b781fb..ee7d969 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -79,6 +79,7 @@ DEB_DEPENDS += libelf-dev libpcap-dev # for libxdp (af_xdp)
 DEB_DEPENDS += iperf3 # for 'make test TEST=vcl'
 DEB_DEPENDS += nasm
 DEB_DEPENDS += iperf ethtool  # for 'make test TEST=vm_vpp_interfaces'
+DEB_DEPENDS += libpcap-dev
 
 LIBFFI=libffi6 # works on all but 20.04 and debian-testing
 
diff --git a/docs/developer/plugins/bpf_trace_filter.rst b/docs/developer/plugins/bpf_trace_filter.rst
new file mode 120000 (symlink)
index 0000000..934d3af
--- /dev/null
@@ -0,0 +1 @@
+../../../src/plugins/bpf_trace_filter/bpf_trace_filter.rst
\ No newline at end of file
index 4af8c4c..91af95f 100644 (file)
@@ -41,3 +41,4 @@ For more on plugins please refer to :ref:`add_plugin`.
     acl_lookup_context
     bufmon_doc
     ip_session_redirect_doc
+    bpf_trace_filter
index d28c6df..a0f80fa 100644 (file)
@@ -102,6 +102,7 @@ bms
 Bn
 boolean
 bootup
+bpf
 Brockners
 bsid
 bss
diff --git a/src/plugins/bpf_trace_filter/CMakeLists.txt b/src/plugins/bpf_trace_filter/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4268022
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (c) 2023 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+vpp_find_path(PCAP_INCLUDE_DIR NAMES pcap.h)
+if (NOT PCAP_INCLUDE_DIR)
+  message(WARNING "libpcap headers not found - bpf_trace_filter plugin disabled")
+  return()
+endif()
+
+vpp_plugin_find_library(bpf_trace_filter PCAP_LIB libpcap.so)
+
+if (NOT PCAP_LIB)
+  message(WARNING "bpf_trace_filter plugin - missing libraries - bpf_trace_filter plugin disabled")
+  return()
+endif()
+
+set(CMAKE_REQUIRED_FLAGS "-fPIC")
+set(CMAKE_REQUIRED_INCLUDES "${PCAP_INCLUDE_DIR}")
+set(CMAKE_REQUIRED_LIBRARIES "${PCAP_LIB}")
+
+include_directories(${PCAP_INCLUDE_DIR})
+
+add_vpp_plugin(bpf_trace_filter
+  SOURCES
+  cli.c
+  plugin.c
+  bpf_trace_filter.c
+  api.c
+
+  API_FILES
+  bpf_trace_filter.api
+
+  LINK_LIBRARIES
+  ${PCAP_LIB}
+)
diff --git a/src/plugins/bpf_trace_filter/FEATURE.yaml b/src/plugins/bpf_trace_filter/FEATURE.yaml
new file mode 100644 (file)
index 0000000..101572f
--- /dev/null
@@ -0,0 +1,8 @@
+---
+name: BPF Trace Filter
+maintainer: Mohammed Hawari <mohammed@hawari.fr>
+features:
+  - BPF Trace Filtering
+description: "BPF Trace Filtering"
+state: experimental
+properties: [CLI, API]
diff --git a/src/plugins/bpf_trace_filter/api.c b/src/plugins/bpf_trace_filter/api.c
new file mode 100644 (file)
index 0000000..9e15c61
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <bpf_trace_filter/bpf_trace_filter.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+/* define message IDs */
+#include <bpf_trace_filter/bpf_trace_filter.api_enum.h>
+#include <bpf_trace_filter/bpf_trace_filter.api_types.h>
+
+#define REPLY_MSG_ID_BASE (bm->msg_id_base)
+#include <vlibapi/api_helper_macros.h>
+
+static void
+vl_api_bpf_trace_filter_set_t_handler (vl_api_bpf_trace_filter_set_t *mp)
+{
+  bpf_trace_filter_main_t *bm = &bpf_trace_filter_main;
+  vl_api_bpf_trace_filter_set_reply_t *rmp;
+  clib_error_t *err = 0;
+  int rv = 0;
+  u8 is_del;
+  char *bpf_expr;
+  is_del = !mp->is_add;
+
+  bpf_expr = vl_api_from_api_to_new_c_string (&mp->filter);
+  err = bpf_trace_filter_set_unset (bpf_expr, is_del);
+
+  if (err)
+    {
+      rv = -1;
+      clib_error_report (err);
+    }
+  vec_free (bpf_expr);
+
+  REPLY_MACRO (VL_API_BPF_TRACE_FILTER_SET_REPLY);
+}
+
+#include <bpf_trace_filter/bpf_trace_filter.api.c>
+
+static clib_error_t *
+bpf_trace_filter_plugin_api_hookup (vlib_main_t *vm)
+{
+  bpf_trace_filter_main_t *bm = &bpf_trace_filter_main;
+
+  /* ask for a correctly-sized block of API message decode slots */
+  bm->msg_id_base = setup_message_id_table ();
+  return 0;
+}
+
+VLIB_API_INIT_FUNCTION (bpf_trace_filter_plugin_api_hookup);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
\ No newline at end of file
diff --git a/src/plugins/bpf_trace_filter/bpf_trace_filter.api b/src/plugins/bpf_trace_filter/bpf_trace_filter.api
new file mode 100644 (file)
index 0000000..53f1b17
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * bpf_trace_filter.api - BPF Trace filter API
+ *
+ * Copyright (c) 2023 Cisco and/or its affiliates
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ option version = "0.1.0";
+
+ autoreply define bpf_trace_filter_set
+ {
+  u32 client_index;
+  u32 context;
+  bool is_add [default = true];
+  string filter[];
+ };
\ No newline at end of file
diff --git a/src/plugins/bpf_trace_filter/bpf_trace_filter.c b/src/plugins/bpf_trace_filter/bpf_trace_filter.c
new file mode 100644 (file)
index 0000000..ff08d2c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <bpf_trace_filter/bpf_trace_filter.h>
+
+clib_error_t *
+bpf_trace_filter_init (vlib_main_t *vm)
+{
+  bpf_trace_filter_main_t *btm = &bpf_trace_filter_main;
+  btm->pcap = pcap_open_dead (DLT_EN10MB, 65535);
+
+  return 0;
+}
+
+int vnet_is_packet_traced (vlib_buffer_t *b, u32 classify_table_index,
+                          int func);
+
+clib_error_t *
+bpf_trace_filter_set_unset (const char *bpf_expr, u8 is_del)
+{
+  bpf_trace_filter_main_t *btm = &bpf_trace_filter_main;
+  if (is_del)
+    {
+      if (btm->prog_set)
+       {
+         btm->prog_set = 0;
+         pcap_freecode (&btm->prog);
+       }
+    }
+  else if (bpf_expr)
+    {
+      if (btm->prog_set)
+       pcap_freecode (&btm->prog);
+      btm->prog_set = 0;
+      if (pcap_compile (btm->pcap, &btm->prog, (char *) bpf_expr, 0,
+                       PCAP_NETMASK_UNKNOWN))
+       {
+         return clib_error_return (0, "Failed pcap_compile of %s", bpf_expr);
+       }
+      btm->prog_set = 1;
+    }
+  return 0;
+};
+
+int
+bpf_is_packed_traced (vlib_buffer_t *b, u32 classify_table_index, int func)
+{
+  bpf_trace_filter_main_t *bfm = &bpf_trace_filter_main;
+  struct pcap_pkthdr phdr = { 0 };
+  int res;
+  int res1;
+  res1 = vnet_is_packet_traced (b, classify_table_index, 0);
+
+  if (res1 != 1)
+    return res1;
+
+  if (!bfm->prog_set)
+    return 1;
+
+  phdr.caplen = b->current_length;
+  phdr.len = b->current_length;
+  res = pcap_offline_filter (&bfm->prog, &phdr, vlib_buffer_get_current (b));
+  return res != 0;
+}
+
+VLIB_REGISTER_TRACE_FILTER_FUNCTION (bpf_trace_filter_fn, static) = {
+  .name = "bpf_trace_filter",
+  .description = "bpf based trace filter",
+  .priority = 10,
+  .function = bpf_is_packed_traced
+};
+
+VLIB_INIT_FUNCTION (bpf_trace_filter_init);
+bpf_trace_filter_main_t bpf_trace_filter_main;
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/bpf_trace_filter/bpf_trace_filter.h b/src/plugins/bpf_trace_filter/bpf_trace_filter.h
new file mode 100644 (file)
index 0000000..a031f98
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef _BPF_TRACE_FILTER_H_
+#define _BPF_TRACE_FILTER_H_
+#include <vlib/vlib.h>
+#include <pcap.h>
+typedef struct
+{
+  pcap_t *pcap;
+  u16 msg_id_base;
+  u8 prog_set;
+  struct bpf_program prog;
+} bpf_trace_filter_main_t;
+
+extern bpf_trace_filter_main_t bpf_trace_filter_main;
+clib_error_t *bpf_trace_filter_set_unset (const char *bpf_expr, u8 is_del);
+#endif /* _BPF_TRACE_FILTER_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
\ No newline at end of file
diff --git a/src/plugins/bpf_trace_filter/bpf_trace_filter.rst b/src/plugins/bpf_trace_filter/bpf_trace_filter.rst
new file mode 100644 (file)
index 0000000..63deddb
--- /dev/null
@@ -0,0 +1,4 @@
+BPF Trace Filter Function
+============================
+This plugin provides a trace filter function that relies on a BPF interpreter to select which packets
+must be traced.
\ No newline at end of file
diff --git a/src/plugins/bpf_trace_filter/cli.c b/src/plugins/bpf_trace_filter/cli.c
new file mode 100644 (file)
index 0000000..906ca71
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#include <stdint.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <inttypes.h>
+
+#include <vlib/vlib.h>
+#include <bpf_trace_filter/bpf_trace_filter.h>
+#include <pcap.h>
+
+static clib_error_t *
+set_bpf_trace_filter_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  u8 *bpf_expr = 0;
+  u8 is_del = 0;
+  clib_error_t *err = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "del"))
+       is_del = 1;
+      else if (unformat (line_input, "%s", &bpf_expr))
+       ;
+      else
+       return clib_error_return (0, "unknown input `%U'",
+                                 format_unformat_error, input);
+    }
+
+  err = bpf_trace_filter_set_unset ((char *) bpf_expr, is_del);
+  unformat_free (line_input);
+
+  return err;
+}
+
+VLIB_CLI_COMMAND (set_bpf_trace_filter, static) = {
+  .path = "set bpf trace filter",
+  .short_help = "set bpf trace filter {<pcap string>}",
+  .function = set_bpf_trace_filter_command_fn,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/bpf_trace_filter/plugin.c b/src/plugins/bpf_trace_filter/plugin.c
new file mode 100644 (file)
index 0000000..db5d611
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2023 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+
+VLIB_PLUGIN_REGISTER () = {
+  .version = VPP_BUILD_VER,
+  .description = "BPF Trace Filter Plugin",
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index bc25ecd..fea4dde 100644 (file)
@@ -29,6 +29,8 @@
  * @param u32 classify_table_index - classifier table index
  * @return 0 => no trace, 1 => trace, -1 => error
  */
+int vnet_is_packet_traced (vlib_buffer_t *b, u32 classify_table_index,
+                          int func);
 
 static inline int
 vnet_is_packet_traced_inline (vlib_buffer_t * b,