libbpf needs a reliable way to distinguish kernels that can support
global percpu data from those that cannot.

Add a dedicated feature probe, so libbpf can make capability decisions
early and fail predictably when global percpu data is unavailable.

Signed-off-by: Leon Hwang <[email protected]>
---
 tools/lib/bpf/features.c        | 35 +++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf_internal.h |  2 ++
 2 files changed, 37 insertions(+)

diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c
index b7e388f99d0b..ef9581c11303 100644
--- a/tools/lib/bpf/features.c
+++ b/tools/lib/bpf/features.c
@@ -620,6 +620,38 @@ static int probe_bpf_syscall_common_attrs(int token_fd)
        return probe_sys_bpf_ext();
 }
 
+static int probe_kern_percpu_data(int token_fd)
+{
+       struct bpf_insn insns[] = {
+               BPF_LD_MAP_VALUE(BPF_REG_1, 0, 0),
+               BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0),
+               BPF_EXIT_INSN(),
+       };
+       LIBBPF_OPTS(bpf_map_create_opts, map_opts,
+               .token_fd = token_fd,
+               .map_flags = token_fd ? BPF_F_TOKEN_FD : 0,
+       );
+       LIBBPF_OPTS(bpf_prog_load_opts, prog_opts,
+               .token_fd = token_fd,
+               .prog_flags = token_fd ? BPF_F_TOKEN_FD : 0,
+       );
+       int ret, map, insn_cnt = ARRAY_SIZE(insns);
+
+       map = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, "libbpf_percpu", 
sizeof(int), 8, 1,
+                            &map_opts);
+       if (map < 0) {
+               pr_warn("Error in %s(): %s. Couldn't create simple percpu_array 
map.\n",
+                       __func__, errstr(map));
+               return map;
+       }
+
+       insns[0].imm = map;
+
+       ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, 
insn_cnt, &prog_opts);
+       close(map);
+       return probe_fd(ret);
+}
+
 typedef int (*feature_probe_fn)(int /* token_fd */);
 
 static struct kern_feature_cache feature_cache;
@@ -707,6 +739,9 @@ static struct kern_feature_desc {
        [FEAT_BPF_SYSCALL_COMMON_ATTRS] = {
                "BPF syscall common attributes support", 
probe_bpf_syscall_common_attrs,
        },
+       [FEAT_PERCPU_DATA] = {
+               "kernel supports percpu data", probe_kern_percpu_data,
+       },
 };
 
 bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id 
feat_id)
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index 04cd303fb5a8..47ae39125f68 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -401,6 +401,8 @@ enum kern_feature_id {
        FEAT_BTF_LAYOUT,
        /* Kernel supports BPF syscall common attributes */
        FEAT_BPF_SYSCALL_COMMON_ATTRS,
+       /* Kernel supports percpu data */
+       FEAT_PERCPU_DATA,
        __FEAT_CNT,
 };
 
-- 
2.54.0


Reply via email to