All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/2] Make BPF skeleton easier to use from C++ code
@ 2022-02-11 22:50 Andrii Nakryiko
  2022-02-11 22:50 ` [PATCH bpf-next 1/2] bpftool: add C++-specific open/load/etc skeleton wrappers Andrii Nakryiko
  2022-02-11 22:50 ` [PATCH bpf-next 2/2] selftests/bpf: add Skeleton templated wrapper as an example Andrii Nakryiko
  0 siblings, 2 replies; 5+ messages in thread
From: Andrii Nakryiko @ 2022-02-11 22:50 UTC (permalink / raw)
  To: bpf, ast, daniel; +Cc: andrii, kernel-team

Add minimal C++-specific additions to BPF skeleton codegen to facilitate
easier use of C skeletons in C++ applications. These additions don't add any
extra ongoing maintenance and allows C++ users to fit pure C skeleton better
into their C++ code base. All that without the need to design, implement and
support a separate C++ BPF skeleton implementation.

Andrii Nakryiko (2):
  bpftool: add C++-specific open/load/etc skeleton wrappers
  selftests/bpf: add Skeleton templated wrapper as an example

 tools/bpf/bpftool/gen.c                  | 26 ++++++-
 tools/testing/selftests/bpf/test_cpp.cpp | 89 +++++++++++++++++++++++-
 2 files changed, 111 insertions(+), 4 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH bpf-next 1/2] bpftool: add C++-specific open/load/etc skeleton wrappers
  2022-02-11 22:50 [PATCH bpf-next 0/2] Make BPF skeleton easier to use from C++ code Andrii Nakryiko
@ 2022-02-11 22:50 ` Andrii Nakryiko
  2022-02-11 23:15   ` Alexei Starovoitov
  2022-02-11 22:50 ` [PATCH bpf-next 2/2] selftests/bpf: add Skeleton templated wrapper as an example Andrii Nakryiko
  1 sibling, 1 reply; 5+ messages in thread
From: Andrii Nakryiko @ 2022-02-11 22:50 UTC (permalink / raw)
  To: bpf, ast, daniel; +Cc: andrii, kernel-team

Add C++-specific static methods for code-generated BPF skeleton for each
skeleton operation: open, open_opts, open_and_load, load, attach,
detach, destroy, and elf_bytes. This is to facilitate easier C++
templating on top of pure C BPF skeleton.

In C, open/load/destroy/etc "methods" are of the form
<skeleton_name>__<method>() to avoid name collision with similar
"methods" of other skeletons withint the same application. This works
well, but is very inconvenient for C++ applications that would like to
write generic (templated) wrappers around BPF skeleton to fit in with
C++ code base and take advantage of destructors and other convenient C++
constructs.

This patch makes it easier to build such generic templated wrappers by
additionally defining C++ static methods for skeleton's struct with
fixed names. This allows to refer to, say, open method as `T::open()`
instead of having to somehow generate `T__open()` function call.

Next patch adds an example template to test_cpp selftest to demonstrate
how it's possible to have all the operations wrapped in a generic
Skeleton<my_skeleton> type without explicitly passing function references.

An example of generated declaration section without %1$s placeholders:

  #ifdef __cplusplus
      static test_attach_probe *open();
      static test_attach_probe *open(const struct bpf_object_open_opts *opts);
      static test_attach_probe *open_and_load();
      static int load(struct test_attach_probe *skel);
      static int attach(struct test_attach_probe *skel);
      static void detach(struct test_attach_probe *skel);
      static void destroy(struct test_attach_probe *skel);
      static const void *elf_bytes(size_t *sz);
  #endif /* __cplusplus */

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/bpf/bpftool/gen.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 6f2e20be0c62..d812414fc587 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -831,6 +831,17 @@ static int do_skeleton(int argc, char **argv)
 
 	codegen("\
 		\n\
+									    \n\
+		#ifdef __cplusplus					    \n\
+			static %1$s *open();				    \n\
+			static %1$s *open(const struct bpf_object_open_opts *opts);\n\
+			static %1$s *open_and_load();			    \n\
+			static int load(struct %1$s *skel);		    \n\
+			static int attach(struct %1$s *skel);		    \n\
+			static void detach(struct %1$s *skel);		    \n\
+			static void destroy(struct %1$s *skel);		    \n\
+			static const void *elf_bytes(size_t *sz);	    \n\
+		#endif /* __cplusplus */				    \n\
 		};							    \n\
 									    \n\
 		static void						    \n\
@@ -1025,9 +1036,20 @@ static int do_skeleton(int argc, char **argv)
 		\";							    \n\
 		}							    \n\
 									    \n\
-		#endif /* %s */						    \n\
+		#ifdef __cplusplus					    \n\
+		struct %1$s *%1$s::open() { return %1$s__open(); }	    \n\
+		struct %1$s *%1$s::open(const struct bpf_object_open_opts *opts) { return %1$s__open_opts(opts); }\n\
+		struct %1$s *%1$s::open_and_load() { return %1$s__open_and_load(); }	\n\
+		int %1$s::load(struct %1$s *skel) { return %1$s__load(skel); }		\n\
+		int %1$s::attach(struct %1$s *skel) { return %1$s__attach(skel); }	\n\
+		void %1$s::detach(struct %1$s *skel) { %1$s__detach(skel); }		\n\
+		void %1$s::destroy(struct %1$s *skel) { %1$s__destroy(skel); }		\n\
+		const void *%1$s::elf_bytes(size_t *sz) { return %1$s__elf_bytes(sz); } \n\
+		#endif /* __cplusplus */				    \n\
+									    \n\
+		#endif /* %2$s */					    \n\
 		",
-		header_guard);
+		obj_name, header_guard);
 	err = 0;
 out:
 	bpf_object__close(obj);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH bpf-next 2/2] selftests/bpf: add Skeleton templated wrapper as an example
  2022-02-11 22:50 [PATCH bpf-next 0/2] Make BPF skeleton easier to use from C++ code Andrii Nakryiko
  2022-02-11 22:50 ` [PATCH bpf-next 1/2] bpftool: add C++-specific open/load/etc skeleton wrappers Andrii Nakryiko
@ 2022-02-11 22:50 ` Andrii Nakryiko
  1 sibling, 0 replies; 5+ messages in thread
From: Andrii Nakryiko @ 2022-02-11 22:50 UTC (permalink / raw)
  To: bpf, ast, daniel; +Cc: andrii, kernel-team

Add an example of how to build C++ template-based BPF skeleton wrapper.
It's an actually runnable valid use of skeleton through more C++-like
interface. Note that skeleton destuction happens implicitly through
Skeleton<T>'s destructor.

Also make test_cpp runnable as it would have crashed on invalid btf
passed into btf_dump__new().

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/testing/selftests/bpf/test_cpp.cpp | 89 +++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/test_cpp.cpp b/tools/testing/selftests/bpf/test_cpp.cpp
index e00201de2890..9eb71643da1b 100644
--- a/tools/testing/selftests/bpf/test_cpp.cpp
+++ b/tools/testing/selftests/bpf/test_cpp.cpp
@@ -5,18 +5,102 @@
 #include <bpf/btf.h>
 #include "test_core_extern.skel.h"
 
-/* do nothing, just make sure we can link successfully */
+template <typename T>
+class Skeleton {
+private:
+	T *skel;
+public:
+	Skeleton(): skel(nullptr) { }
+
+	~Skeleton() { if (skel) T::destroy(skel); }
+
+	int open() { return open(nullptr); }
+
+	int open(const struct bpf_object_open_opts *opts)
+	{
+		int err;
+
+		if (skel)
+			return -EBUSY;
+
+		skel = T::open(opts);
+		err = libbpf_get_error(skel);
+		if (err) {
+			skel = nullptr;
+			return err;
+		}
+
+		return 0;
+	}
+
+	int load() { return T::load(skel); }
+
+	int attach() { return T::attach(skel); }
+
+	void detach() { return T::detach(skel); }
+
+	const T* operator->() const { return skel; }
+
+	T* operator->() { return skel; }
+
+	const T *get() const { return skel; }
+};
 
 static void dump_printf(void *ctx, const char *fmt, va_list args)
 {
 }
 
+static void try_skeleton_template()
+{
+	Skeleton<test_core_extern> skel;
+	std::string prog_name;
+	int err;
+	LIBBPF_OPTS(bpf_object_open_opts, opts);
+
+	err = skel.open(&opts);
+	if (err) {
+		fprintf(stderr, "Skeleton open failed: %d\n", err);
+		return;
+	}
+
+	skel->data->kern_ver = 123;
+	skel->data->int_val = skel->data->ushort_val;
+
+	err = skel.load();
+	if (err) {
+		fprintf(stderr, "Skeleton load failed: %d\n", err);
+		return;
+	}
+
+	if (!skel->kconfig->CONFIG_BPF_SYSCALL)
+		fprintf(stderr, "Seems like CONFIG_BPF_SYSCALL isn't set?!\n");
+
+	err = skel.attach();
+	if (err) {
+		fprintf(stderr, "Skeleton attach failed: %d\n", err);
+		return;
+	}
+
+	prog_name = bpf_program__name(skel->progs.handle_sys_enter);
+	if (prog_name != "handle_sys_enter")
+		fprintf(stderr, "Unexpected program name: %s\n", prog_name.c_str());
+
+	bpf_link__destroy(skel->links.handle_sys_enter);
+	skel->links.handle_sys_enter = bpf_program__attach(skel->progs.handle_sys_enter);
+
+	skel.detach();
+
+	/* destructor will destory underlying skeleton */
+}
+
 int main(int argc, char *argv[])
 {
 	struct btf_dump_opts opts = { };
 	struct test_core_extern *skel;
 	struct btf *btf;
 
+	try_skeleton_template();
+
 	/* libbpf.h */
 	libbpf_set_print(NULL);
 
@@ -25,7 +109,8 @@ int main(int argc, char *argv[])
 
 	/* btf.h */
 	btf = btf__new(NULL, 0);
-	btf_dump__new(btf, dump_printf, nullptr, &opts);
+	if (!libbpf_get_error(btf))
+		btf_dump__new(btf, dump_printf, nullptr, &opts);
 
 	/* BPF skeleton */
 	skel = test_core_extern__open_and_load();
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next 1/2] bpftool: add C++-specific open/load/etc skeleton wrappers
  2022-02-11 22:50 ` [PATCH bpf-next 1/2] bpftool: add C++-specific open/load/etc skeleton wrappers Andrii Nakryiko
@ 2022-02-11 23:15   ` Alexei Starovoitov
  2022-02-11 23:32     ` Andrii Nakryiko
  0 siblings, 1 reply; 5+ messages in thread
From: Alexei Starovoitov @ 2022-02-11 23:15 UTC (permalink / raw)
  To: Andrii Nakryiko; +Cc: bpf, ast, daniel, kernel-team

On Fri, Feb 11, 2022 at 02:50:06PM -0800, Andrii Nakryiko wrote:
>  		}							    \n\
>  									    \n\
> -		#endif /* %s */						    \n\
> +		#ifdef __cplusplus					    \n\
> +		struct %1$s *%1$s::open() { return %1$s__open(); }	    \n\
> +		struct %1$s *%1$s::open(const struct bpf_object_open_opts *opts) { return %1$s__open_opts(opts); }\n\

Why two methods? instead of "opts = nullptr" ?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH bpf-next 1/2] bpftool: add C++-specific open/load/etc skeleton wrappers
  2022-02-11 23:15   ` Alexei Starovoitov
@ 2022-02-11 23:32     ` Andrii Nakryiko
  0 siblings, 0 replies; 5+ messages in thread
From: Andrii Nakryiko @ 2022-02-11 23:32 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Andrii Nakryiko, bpf, Alexei Starovoitov, Daniel Borkmann, Kernel Team

On Fri, Feb 11, 2022 at 3:16 PM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Fri, Feb 11, 2022 at 02:50:06PM -0800, Andrii Nakryiko wrote:
> >               }                                                           \n\
> >                                                                           \n\
> > -             #endif /* %s */                                             \n\
> > +             #ifdef __cplusplus                                          \n\
> > +             struct %1$s *%1$s::open() { return %1$s__open(); }          \n\
> > +             struct %1$s *%1$s::open(const struct bpf_object_open_opts *opts) { return %1$s__open_opts(opts); }\n\
>
> Why two methods? instead of "opts = nullptr" ?

Because my C++ is rusty :) I'll drop no-arg version in v2.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-02-11 23:33 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-11 22:50 [PATCH bpf-next 0/2] Make BPF skeleton easier to use from C++ code Andrii Nakryiko
2022-02-11 22:50 ` [PATCH bpf-next 1/2] bpftool: add C++-specific open/load/etc skeleton wrappers Andrii Nakryiko
2022-02-11 23:15   ` Alexei Starovoitov
2022-02-11 23:32     ` Andrii Nakryiko
2022-02-11 22:50 ` [PATCH bpf-next 2/2] selftests/bpf: add Skeleton templated wrapper as an example Andrii Nakryiko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.