From: Grant Seltzer <grantseltzer@xxxxxxxxx> This adds a new API function used to retrieve all data from a percpu array or percpu hashmap. This is useful because the current interface for doing so requires knowledge of the layout of these BPF map internal structures. Signed-off-by: Grant Seltzer <grantseltzer@xxxxxxxxx> --- tools/lib/bpf/libbpf.c | 28 ++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.h | 25 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 873a29ce7781..8d72cff22688 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -36,6 +36,7 @@ #include <linux/perf_event.h> #include <linux/ring_buffer.h> #include <linux/version.h> +#include <linux/math.h> #include <sys/epoll.h> #include <sys/ioctl.h> #include <sys/mman.h> @@ -4370,6 +4371,33 @@ int bpf_map__resize(struct bpf_map *map, __u32 max_entries) return bpf_map__set_max_entries(map, max_entries); } +void *bpf_map__get_percpu_value(const struct bpf_map *map, const void *key) +{ + + if (!(bpf_map__type(map) == BPF_MAP_TYPE_PERCPU_ARRAY || + bpf_map__type(map) == BPF_MAP_TYPE_PERCPU_HASH)) { + return libbpf_err_ptr(-EINVAL); + } + + int num_cpus; + __u32 value_size; + num_cpus = libbpf_num_possible_cpus(); + + if (num_cpus < 0) + return libbpf_err_ptr(-EBUSY); + + value_size = bpf_map__value_size(map); + + void *data = malloc(roundup(value_size, 8) * num_cpus); + int err = bpf_map_lookup_elem(map->fd, key, data); + if (err) { + free(data); + return libbpf_err_ptr(err); + } + + return data; +} + static int bpf_object__probe_loading(struct bpf_object *obj) { diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index cdbfee60ea3e..99b218702dfb 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -921,6 +921,31 @@ LIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize LIBBPF_DEPRECATED_SINCE(0, 8, "use bpf_map__type() instead") LIBBPF_API bool bpf_map__is_offload_neutral(const struct bpf_map *map); +/** + * @brief **bpf_map__get_percpu_value()** returns a pointer to an array + * of data stored in a per-cpu array or per-cpu hashmap at a specified + * key. Each element is padded to 8 bytes regardless of the value data + * type stored in the per-cpu map. The index of each element in the array + * corresponds with the cpu that the data was set from. + * @param map per-cpu array or per-cpu hashmap + * @param key the key or index in the map + * @return pointer to the array of data + * + * example usage: + * + * values = bpf_map__get_percpu_value(bpfmap, (void*)&zero); + * if (values == NULL) { + * // error handling + * } + * + * void* ptr = values; + * for (int i = 0; i < num_cpus; i++) { + * printf("CPU %d: %ld\n", i, *(ulong*)ptr); + * ptr += 8; + * } + */ +LIBBPF_API void *bpf_map__get_percpu_value(const struct bpf_map *map, const void *key); + /** * @brief **bpf_map__is_internal()** tells the caller whether or not the * passed map is a special map created by libbpf automatically for things like -- 2.34.1