History

selftests/bpf: Add Skeleton templated wrapper as an example

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().

Andrii Nakryiko committed 4 years ago

Commit 189e0ec1 parent bb8ffe61 file · +85 −2Browse files

Showing the changes to tools/testing/selftests/bpf/test_cpp.cpp (1 of 1 file). Show all

Unified · Split

tools/testing/selftests/bpf/test_cpp.cpp+85−2
@@ -5,18 +5,100 @@ · 4 unmodified lines
55 #include <bpf/btf.h>
66 #include "test_core_extern.skel.h"
77
8−/* do nothing, just make sure we can link successfully */
8+template <typename T>
9+class Skeleton {
10+private:
11+ T *skel;
12+public:
13+ Skeleton(): skel(nullptr) { }
14+
15+ ~Skeleton() { if (skel) T::destroy(skel); }
16+
17+ int open(const struct bpf_object_open_opts *opts = nullptr)
18+ {
19+ int err;
20+
21+ if (skel)
22+ return -EBUSY;
23+
24+ skel = T::open(opts);
25+ err = libbpf_get_error(skel);
26+ if (err) {
27+ skel = nullptr;
28+ return err;
29+ }
30+
31+ return 0;
32+ }
33+
34+ int load() { return T::load(skel); }
35+
36+ int attach() { return T::attach(skel); }
37+
38+ void detach() { return T::detach(skel); }
39+
40+ const T* operator->() const { return skel; }
41+
42+ T* operator->() { return skel; }
43+
44+ const T *get() const { return skel; }
45+};
946
1047 static void dump_printf(void *ctx, const char *fmt, va_list args)
1148 {
1249 }
1350
51+static void try_skeleton_template()
52+{
53+ Skeleton<test_core_extern> skel;
54+ std::string prog_name;
55+ int err;
56+ LIBBPF_OPTS(bpf_object_open_opts, opts);
57+
58+ err = skel.open(&opts);
59+ if (err) {
60+ fprintf(stderr, "Skeleton open failed: %d\n", err);
61+ return;
62+ }
63+
64+ skel->data->kern_ver = 123;
65+ skel->data->int_val = skel->data->ushort_val;
66+
67+ err = skel.load();
68+ if (err) {
69+ fprintf(stderr, "Skeleton load failed: %d\n", err);
70+ return;
71+ }
72+
73+ if (!skel->kconfig->CONFIG_BPF_SYSCALL)
74+ fprintf(stderr, "Seems like CONFIG_BPF_SYSCALL isn't set?!\n");
75+
76+ err = skel.attach();
77+ if (err) {
78+ fprintf(stderr, "Skeleton attach failed: %d\n", err);
79+ return;
80+ }
81+
82+ prog_name = bpf_program__name(skel->progs.handle_sys_enter);
83+ if (prog_name != "handle_sys_enter")
84+ fprintf(stderr, "Unexpected program name: %s\n", prog_name.c_str());
85+
86+ bpf_link__destroy(skel->links.handle_sys_enter);
87+ skel->links.handle_sys_enter = bpf_program__attach(skel->progs.handle_sys_enter);
88+
89+ skel.detach();
90+
91+ /* destructor will destory underlying skeleton */
92+}
93+
1494 int main(int argc, char *argv[])
1595 {
1696 struct btf_dump_opts opts = { };
1797 struct test_core_extern *skel;
1898 struct btf *btf;
1999
100+ try_skeleton_template();
101+
20102 /* libbpf.h */
21103 libbpf_set_print(NULL);
22104
@@ -25,7 +107,8 @@ int main(int argc, char *argv[]) · 2 unmodified lines
25107
26108 /* btf.h */
27109 btf = btf__new(NULL, 0);
28− btf_dump__new(btf, dump_printf, nullptr, &opts);
110+ if (!libbpf_get_error(btf))
111+ btf_dump__new(btf, dump_printf, nullptr, &opts);
29112
30113 /* BPF skeleton */
31114 skel = test_core_extern__open_and_load();