[PATCH bpf-next 13/16] bpftool: Emit the arena percpu datasec into skeleton

From: Xu Kuohai

Date: Tue Oct 20 2026 - 10:13:29 EST


From: Xu Kuohai <xukuohai@xxxxxxxxxx>

Emit the arena percpu data into skeleton.

For an object with

__u64 arena_global __arena;
__u64 __arena_percpu data1;
__u64 __arena_percpu data2;

the skeleton gets two data sections for the arena map

struct obj__arena {
__u64 arena_global;
} *arena;

struct obj__arena_percpu {
__u64 data1;
__u64 data2;
} *arena_percpu;

and the load function points arena_percpu at cpu 0's chunk

static inline int
obj__load(struct obj *obj)
{
int err;

err = bpf_object__load_skeleton(obj->skeleton);
if (err)
return err;

obj->arena_percpu = bpf_map__arena_percpu_base(obj->maps.arena);

return 0;
}

Other cpus can be accessed through bpf_map__arena_percpu_ptr().

For an object with only

__u64 __arena_percpu counter;

the skeleton carries a single arena_percpu section

struct obj__arena_percpu {
__u64 counter;
} *arena_percpu;

Signed-off-by: Xu Kuohai <xukuohai@xxxxxxxxxx>
---
tools/bpf/bpftool/gen.c | 69 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 64 insertions(+), 5 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index ee680f7c2116..8a321ec1155a 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -132,6 +132,10 @@ static bool get_datasec_ident(const char *sec_name, char *buf, size_t buf_sz)
snprintf(buf, buf_sz, "arena");
return true;
}
+ if (strcmp(sec_name, ".arena.percpu") == 0) {
+ snprintf(buf, buf_sz, "arena_percpu");
+ return true;
+ }
for (i = 0, n = ARRAY_SIZE(pfxs); i < n; i++) {
const char *pfx = pfxs[i];

@@ -326,6 +330,14 @@ static int codegen_datasecs(struct bpf_object *obj, const char *obj_name)
}
}

+ /* expose arena percpu as a separate data section */
+ sec = find_type_for_map(btf, "arena_percpu");
+ if (sec) {
+ err = codegen_datasec_def(obj, btf, d, sec, obj_name);
+ if (err)
+ goto out;
+ }
+

out:
btf_dump__free(d);
@@ -1511,11 +1523,58 @@ static int do_skeleton(int argc, char **argv)
return %1$s__open_opts(NULL); \n\
} \n\
\n\
- static inline int \n\
- %1$s__load(struct %1$s *obj) \n\
- { \n\
- return bpf_object__load_skeleton(obj->skeleton); \n\
- } \n\
+ ",
+ obj_name
+ );
+
+ /* The per-cpu arena data has no mmaped slot in the map skeleton.
+ * Point obj->arena_percpu at cpu 0's chunk once the object is
+ * loaded.
+ */
+ {
+ char arena_map_ident[256] = "";
+ bool have_percpu_arena = false;
+
+ bpf_object__for_each_map(map, obj) {
+ if (bpf_map__type(map) != BPF_MAP_TYPE_ARENA)
+ continue;
+ if (find_type_for_map(bpf_object__btf(obj), "arena_percpu") &&
+ get_map_ident(map, arena_map_ident, sizeof(arena_map_ident))) {
+ have_percpu_arena = true;
+ break;
+ }
+ }
+
+ if (have_percpu_arena) {
+ codegen("\
+ \n\
+ static inline int \n\
+ %1$s__load(struct %1$s *obj) \n\
+ { \n\
+ int err; \n\
+ \n\
+ err = bpf_object__load_skeleton(obj->skeleton); \n\
+ if (err) \n\
+ return err; \n\
+ obj->arena_percpu = \n\
+ bpf_map__arena_percpu_base(obj->maps.%2$s); \n\
+ return 0; \n\
+ } \n\
+ ", obj_name, arena_map_ident);
+ } else {
+ codegen("\
+ \n\
+ static inline int \n\
+ %1$s__load(struct %1$s *obj) \n\
+ { \n\
+ return bpf_object__load_skeleton(obj->skeleton); \n\
+ } \n\
+ ", obj_name);
+ }
+ }
+
+ codegen("\
+ \n\
\n\
static inline struct %1$s * \n\
%1$s__open_and_load(void) \n\
--
2.47.3