Merge branch 'libbpf-versioning-doc'
Andrey Ignatov says: ==================== This patch set adds ABI versioning and documentation to libbpf. Patch 1 renames btf_get_from_id to btf__get_from_id to follow naming convention. Patch 2 adds version script and has more details on ABI versioning. Patch 3 adds simple check that all global symbols are versioned. Patch 4 documents a few aspects of libbpf API and ABI in dev process. v1->v2: * add patch from Martin KaFai Lau <kafai@fb.com> to rename btf_get_from_id; * add documentation for libbpf API and ABI. ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
17d95e4225
|
@ -713,7 +713,7 @@ static int do_dump(int argc, char **argv)
|
||||||
|
|
||||||
prev_key = NULL;
|
prev_key = NULL;
|
||||||
|
|
||||||
err = btf_get_from_id(info.btf_id, &btf);
|
err = btf__get_from_id(info.btf_id, &btf);
|
||||||
if (err) {
|
if (err) {
|
||||||
p_err("failed to get btf");
|
p_err("failed to get btf");
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
|
@ -857,7 +857,7 @@ static int do_lookup(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* here means bpf_map_lookup_elem() succeeded */
|
/* here means bpf_map_lookup_elem() succeeded */
|
||||||
err = btf_get_from_id(info.btf_id, &btf);
|
err = btf__get_from_id(info.btf_id, &btf);
|
||||||
if (err) {
|
if (err) {
|
||||||
p_err("failed to get btf");
|
p_err("failed to get btf");
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
|
|
|
@ -622,7 +622,7 @@ static int do_dump(int argc, char **argv)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.btf_id && btf_get_from_id(info.btf_id, &btf)) {
|
if (info.btf_id && btf__get_from_id(info.btf_id, &btf)) {
|
||||||
p_err("failed to get btf");
|
p_err("failed to get btf");
|
||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,12 @@ include $(srctree)/tools/build/Makefile.include
|
||||||
|
|
||||||
BPF_IN := $(OUTPUT)libbpf-in.o
|
BPF_IN := $(OUTPUT)libbpf-in.o
|
||||||
LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE))
|
LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE))
|
||||||
|
VERSION_SCRIPT := libbpf.map
|
||||||
|
|
||||||
|
GLOBAL_SYM_COUNT = $(shell readelf -s $(BPF_IN) | \
|
||||||
|
awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {s++} END{print s}')
|
||||||
|
VERSIONED_SYM_COUNT = $(shell readelf -s $(OUTPUT)libbpf.so | \
|
||||||
|
grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 | sort -u | wc -l)
|
||||||
|
|
||||||
CMD_TARGETS = $(LIB_FILE)
|
CMD_TARGETS = $(LIB_FILE)
|
||||||
|
|
||||||
|
@ -158,7 +164,7 @@ TARGETS = $(CMD_TARGETS)
|
||||||
|
|
||||||
all: fixdep all_cmd
|
all: fixdep all_cmd
|
||||||
|
|
||||||
all_cmd: $(CMD_TARGETS)
|
all_cmd: $(CMD_TARGETS) check
|
||||||
|
|
||||||
$(BPF_IN): force elfdep bpfdep
|
$(BPF_IN): force elfdep bpfdep
|
||||||
@(test -f ../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \
|
@(test -f ../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \
|
||||||
|
@ -176,7 +182,8 @@ $(BPF_IN): force elfdep bpfdep
|
||||||
$(Q)$(MAKE) $(build)=libbpf
|
$(Q)$(MAKE) $(build)=libbpf
|
||||||
|
|
||||||
$(OUTPUT)libbpf.so: $(BPF_IN)
|
$(OUTPUT)libbpf.so: $(BPF_IN)
|
||||||
$(QUIET_LINK)$(CC) --shared $^ -o $@
|
$(QUIET_LINK)$(CC) --shared -Wl,--version-script=$(VERSION_SCRIPT) \
|
||||||
|
$^ -o $@
|
||||||
|
|
||||||
$(OUTPUT)libbpf.a: $(BPF_IN)
|
$(OUTPUT)libbpf.a: $(BPF_IN)
|
||||||
$(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
|
$(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
|
||||||
|
@ -184,6 +191,18 @@ $(OUTPUT)libbpf.a: $(BPF_IN)
|
||||||
$(OUTPUT)test_libbpf: test_libbpf.cpp $(OUTPUT)libbpf.a
|
$(OUTPUT)test_libbpf: test_libbpf.cpp $(OUTPUT)libbpf.a
|
||||||
$(QUIET_LINK)$(CXX) $^ -lelf -o $@
|
$(QUIET_LINK)$(CXX) $^ -lelf -o $@
|
||||||
|
|
||||||
|
check: check_abi
|
||||||
|
|
||||||
|
check_abi: $(OUTPUT)libbpf.so
|
||||||
|
@if [ "$(GLOBAL_SYM_COUNT)" != "$(VERSIONED_SYM_COUNT)" ]; then \
|
||||||
|
echo "Warning: Num of global symbols in $(BPF_IN)" \
|
||||||
|
"($(GLOBAL_SYM_COUNT)) does NOT match with num of" \
|
||||||
|
"versioned symbols in $^ ($(VERSIONED_SYM_COUNT))." \
|
||||||
|
"Please make sure all LIBBPF_API symbols are" \
|
||||||
|
"versioned in $(VERSION_SCRIPT)." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
define do_install
|
define do_install
|
||||||
if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
|
if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
|
||||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
|
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
libbpf API naming convention
|
||||||
|
============================
|
||||||
|
|
||||||
|
libbpf API provides access to a few logically separated groups of
|
||||||
|
functions and types. Every group has its own naming convention
|
||||||
|
described here. It's recommended to follow these conventions whenever a
|
||||||
|
new function or type is added to keep libbpf API clean and consistent.
|
||||||
|
|
||||||
|
All types and functions provided by libbpf API should have one of the
|
||||||
|
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``.
|
||||||
|
|
||||||
|
System call wrappers
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
System call wrappers are simple wrappers for commands supported by
|
||||||
|
sys_bpf system call. These wrappers should go to ``bpf.h`` header file
|
||||||
|
and map one-on-one to corresponding commands.
|
||||||
|
|
||||||
|
For example ``bpf_map_lookup_elem`` wraps ``BPF_MAP_LOOKUP_ELEM``
|
||||||
|
command of sys_bpf, ``bpf_prog_attach`` wraps ``BPF_PROG_ATTACH``, etc.
|
||||||
|
|
||||||
|
Objects
|
||||||
|
-------
|
||||||
|
|
||||||
|
Another class of types and functions provided by libbpf API is "objects"
|
||||||
|
and functions to work with them. Objects are high-level abstractions
|
||||||
|
such as BPF program or BPF map. They're represented by corresponding
|
||||||
|
structures such as ``struct bpf_object``, ``struct bpf_program``,
|
||||||
|
``struct bpf_map``, etc.
|
||||||
|
|
||||||
|
Structures are forward declared and access to their fields should be
|
||||||
|
provided via corresponding getters and setters rather than directly.
|
||||||
|
|
||||||
|
These objects are associated with corresponding parts of ELF object that
|
||||||
|
contains compiled BPF programs.
|
||||||
|
|
||||||
|
For example ``struct bpf_object`` represents ELF object itself created
|
||||||
|
from an ELF file or from a buffer, ``struct bpf_program`` represents a
|
||||||
|
program in ELF object and ``struct bpf_map`` is a map.
|
||||||
|
|
||||||
|
Functions that work with an object have names built from object name,
|
||||||
|
double underscore and part that describes function purpose.
|
||||||
|
|
||||||
|
For example ``bpf_object__open`` consists of the name of corresponding
|
||||||
|
object, ``bpf_object``, double underscore and ``open`` that defines the
|
||||||
|
purpose of the function to open ELF file and create ``bpf_object`` from
|
||||||
|
it.
|
||||||
|
|
||||||
|
Another example: ``bpf_program__load`` is named for corresponding
|
||||||
|
object, ``bpf_program``, that is separated from other part of the name
|
||||||
|
by double underscore.
|
||||||
|
|
||||||
|
All objects and corresponding functions other than BTF related should go
|
||||||
|
to ``libbpf.h``. BTF types and functions should go to ``btf.h``.
|
||||||
|
|
||||||
|
Auxiliary functions
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Auxiliary functions and types that don't fit well in any of categories
|
||||||
|
described above should have ``libbpf_`` prefix, e.g.
|
||||||
|
``libbpf_get_error`` or ``libbpf_prog_type_by_name``.
|
||||||
|
|
||||||
|
libbpf ABI
|
||||||
|
==========
|
||||||
|
|
||||||
|
libbpf can be both linked statically or used as DSO. To avoid possible
|
||||||
|
conflicts with other libraries an application is linked with, all
|
||||||
|
non-static libbpf symbols should have one of the prefixes mentioned in
|
||||||
|
API documentation above. See API naming convention to choose the right
|
||||||
|
name for a new symbol.
|
||||||
|
|
||||||
|
Symbol visibility
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
libbpf follow the model when all global symbols have visibility "hidden"
|
||||||
|
by default and to make a symbol visible it has to be explicitly
|
||||||
|
attributed with ``LIBBPF_API`` macro. For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||||
|
|
||||||
|
This prevents from accidentally exporting a symbol, that is not supposed
|
||||||
|
to be a part of ABI what, in turn, improves both libbpf developer- and
|
||||||
|
user-experiences.
|
||||||
|
|
||||||
|
ABI versionning
|
||||||
|
---------------
|
||||||
|
|
||||||
|
To make future ABI extensions possible libbpf ABI is versioned.
|
||||||
|
Versioning is implemented by ``libbpf.map`` version script that is
|
||||||
|
passed to linker.
|
||||||
|
|
||||||
|
Version name is ``LIBBPF_`` prefix + three-component numeric version,
|
||||||
|
starting from ``0.0.1``.
|
||||||
|
|
||||||
|
Every time ABI is being changed, e.g. because a new symbol is added or
|
||||||
|
semantic of existing symbol is changed, ABI version should be bumped.
|
||||||
|
|
||||||
|
For example, if current state of ``libbpf.map`` is:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
LIBBPF_0.0.1 {
|
||||||
|
global:
|
||||||
|
bpf_func_a;
|
||||||
|
bpf_func_b;
|
||||||
|
local:
|
||||||
|
\*;
|
||||||
|
};
|
||||||
|
|
||||||
|
, and a new symbol ``bpf_func_c`` is being introduced, then
|
||||||
|
``libbpf.map`` should be changed like this:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
LIBBPF_0.0.1 {
|
||||||
|
global:
|
||||||
|
bpf_func_a;
|
||||||
|
bpf_func_b;
|
||||||
|
local:
|
||||||
|
\*;
|
||||||
|
};
|
||||||
|
LIBBPF_0.0.2 {
|
||||||
|
global:
|
||||||
|
bpf_func_c;
|
||||||
|
} LIBBPF_0.0.1;
|
||||||
|
|
||||||
|
, where new version ``LIBBPF_0.0.2`` depends on the previous
|
||||||
|
``LIBBPF_0.0.1``.
|
||||||
|
|
||||||
|
Format of version script and ways to handle ABI changes, including
|
||||||
|
incompatible ones, described in details in [1].
|
||||||
|
|
||||||
|
Links
|
||||||
|
=====
|
||||||
|
|
||||||
|
[1] https://www.akkadia.org/drepper/dsohowto.pdf
|
||||||
|
(Chapter 3. Maintaining APIs and ABIs).
|
|
@ -415,7 +415,7 @@ const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btf_get_from_id(__u32 id, struct btf **btf)
|
int btf__get_from_id(__u32 id, struct btf **btf)
|
||||||
{
|
{
|
||||||
struct bpf_btf_info btf_info = { 0 };
|
struct bpf_btf_info btf_info = { 0 };
|
||||||
__u32 len = sizeof(btf_info);
|
__u32 len = sizeof(btf_info);
|
||||||
|
|
|
@ -73,7 +73,7 @@ LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
|
||||||
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
||||||
LIBBPF_API int btf__fd(const struct btf *btf);
|
LIBBPF_API int btf__fd(const struct btf *btf);
|
||||||
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
||||||
LIBBPF_API int btf_get_from_id(__u32 id, struct btf **btf);
|
LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
|
||||||
|
|
||||||
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
|
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
|
||||||
void btf_ext__free(struct btf_ext *btf_ext);
|
void btf_ext__free(struct btf_ext *btf_ext);
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
LIBBPF_0.0.1 {
|
||||||
|
global:
|
||||||
|
bpf_btf_get_fd_by_id;
|
||||||
|
bpf_create_map;
|
||||||
|
bpf_create_map_in_map;
|
||||||
|
bpf_create_map_in_map_node;
|
||||||
|
bpf_create_map_name;
|
||||||
|
bpf_create_map_node;
|
||||||
|
bpf_create_map_xattr;
|
||||||
|
bpf_load_btf;
|
||||||
|
bpf_load_program;
|
||||||
|
bpf_load_program_xattr;
|
||||||
|
bpf_map__btf_key_type_id;
|
||||||
|
bpf_map__btf_value_type_id;
|
||||||
|
bpf_map__def;
|
||||||
|
bpf_map__fd;
|
||||||
|
bpf_map__is_offload_neutral;
|
||||||
|
bpf_map__name;
|
||||||
|
bpf_map__next;
|
||||||
|
bpf_map__pin;
|
||||||
|
bpf_map__prev;
|
||||||
|
bpf_map__priv;
|
||||||
|
bpf_map__reuse_fd;
|
||||||
|
bpf_map__set_ifindex;
|
||||||
|
bpf_map__set_inner_map_fd;
|
||||||
|
bpf_map__set_priv;
|
||||||
|
bpf_map__unpin;
|
||||||
|
bpf_map_delete_elem;
|
||||||
|
bpf_map_get_fd_by_id;
|
||||||
|
bpf_map_get_next_id;
|
||||||
|
bpf_map_get_next_key;
|
||||||
|
bpf_map_lookup_and_delete_elem;
|
||||||
|
bpf_map_lookup_elem;
|
||||||
|
bpf_map_update_elem;
|
||||||
|
bpf_obj_get;
|
||||||
|
bpf_obj_get_info_by_fd;
|
||||||
|
bpf_obj_pin;
|
||||||
|
bpf_object__btf_fd;
|
||||||
|
bpf_object__close;
|
||||||
|
bpf_object__find_map_by_name;
|
||||||
|
bpf_object__find_map_by_offset;
|
||||||
|
bpf_object__find_program_by_title;
|
||||||
|
bpf_object__kversion;
|
||||||
|
bpf_object__load;
|
||||||
|
bpf_object__name;
|
||||||
|
bpf_object__next;
|
||||||
|
bpf_object__open;
|
||||||
|
bpf_object__open_buffer;
|
||||||
|
bpf_object__open_xattr;
|
||||||
|
bpf_object__pin;
|
||||||
|
bpf_object__pin_maps;
|
||||||
|
bpf_object__pin_programs;
|
||||||
|
bpf_object__priv;
|
||||||
|
bpf_object__set_priv;
|
||||||
|
bpf_object__unload;
|
||||||
|
bpf_object__unpin_maps;
|
||||||
|
bpf_object__unpin_programs;
|
||||||
|
bpf_perf_event_read_simple;
|
||||||
|
bpf_prog_attach;
|
||||||
|
bpf_prog_detach;
|
||||||
|
bpf_prog_detach2;
|
||||||
|
bpf_prog_get_fd_by_id;
|
||||||
|
bpf_prog_get_next_id;
|
||||||
|
bpf_prog_load;
|
||||||
|
bpf_prog_load_xattr;
|
||||||
|
bpf_prog_query;
|
||||||
|
bpf_prog_test_run;
|
||||||
|
bpf_program__fd;
|
||||||
|
bpf_program__is_kprobe;
|
||||||
|
bpf_program__is_perf_event;
|
||||||
|
bpf_program__is_raw_tracepoint;
|
||||||
|
bpf_program__is_sched_act;
|
||||||
|
bpf_program__is_sched_cls;
|
||||||
|
bpf_program__is_socket_filter;
|
||||||
|
bpf_program__is_tracepoint;
|
||||||
|
bpf_program__is_xdp;
|
||||||
|
bpf_program__load;
|
||||||
|
bpf_program__next;
|
||||||
|
bpf_program__nth_fd;
|
||||||
|
bpf_program__pin;
|
||||||
|
bpf_program__pin_instance;
|
||||||
|
bpf_program__prev;
|
||||||
|
bpf_program__priv;
|
||||||
|
bpf_program__set_expected_attach_type;
|
||||||
|
bpf_program__set_ifindex;
|
||||||
|
bpf_program__set_kprobe;
|
||||||
|
bpf_program__set_perf_event;
|
||||||
|
bpf_program__set_prep;
|
||||||
|
bpf_program__set_priv;
|
||||||
|
bpf_program__set_raw_tracepoint;
|
||||||
|
bpf_program__set_sched_act;
|
||||||
|
bpf_program__set_sched_cls;
|
||||||
|
bpf_program__set_socket_filter;
|
||||||
|
bpf_program__set_tracepoint;
|
||||||
|
bpf_program__set_type;
|
||||||
|
bpf_program__set_xdp;
|
||||||
|
bpf_program__title;
|
||||||
|
bpf_program__unload;
|
||||||
|
bpf_program__unpin;
|
||||||
|
bpf_program__unpin_instance;
|
||||||
|
bpf_raw_tracepoint_open;
|
||||||
|
bpf_set_link_xdp_fd;
|
||||||
|
bpf_task_fd_query;
|
||||||
|
bpf_verify_program;
|
||||||
|
btf__fd;
|
||||||
|
btf__find_by_name;
|
||||||
|
btf__free;
|
||||||
|
btf__get_from_id;
|
||||||
|
btf__name_by_offset;
|
||||||
|
btf__new;
|
||||||
|
btf__resolve_size;
|
||||||
|
btf__resolve_type;
|
||||||
|
btf__type_by_id;
|
||||||
|
libbpf_attach_type_by_name;
|
||||||
|
libbpf_get_error;
|
||||||
|
libbpf_prog_type_by_name;
|
||||||
|
libbpf_set_print;
|
||||||
|
libbpf_strerror;
|
||||||
|
local:
|
||||||
|
*;
|
||||||
|
};
|
|
@ -2585,7 +2585,7 @@ static int do_test_file(unsigned int test_num)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = btf_get_from_id(info.btf_id, &btf);
|
err = btf__get_from_id(info.btf_id, &btf);
|
||||||
if (CHECK(err, "cannot get btf from kernel, err: %d", err))
|
if (CHECK(err, "cannot get btf from kernel, err: %d", err))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue