mbox series

[bpf-next,v6,0/5] Create shadow types for struct_ops maps in skeletons

Message ID 20240229064523.2091270-1-thinker.li@gmail.com (mailing list archive)
Headers show
Series Create shadow types for struct_ops maps in skeletons | expand

Message

Kui-Feng Lee Feb. 29, 2024, 6:45 a.m. UTC
This patchset allows skeleton users to change the values of the fields
in struct_ops maps at runtime. It will create a shadow type pointer in
a skeleton for each struct_ops map, allowing users to access the
values of fields through these pointers. For instance, if there is an
integer field named "FOO" in a struct_ops map called "testmap", you
can access the value of "FOO" in this way.


    skel->struct_ops.testmap->FOO = 13;

With this feature, the users can pass flags or other data along with
the map from the user space to the kernel without creating separate
struct_ops map for different values in BPF.

== Shadow Type ==

The shadow type of a struct_ops map is a variant of the original
struct type of the map. The code generator translates each field in
the original struct type to a field in the shadow type. The type of a
field in the shadow type may not be the same as the corresponding
field in the original struct type. For example, modifiers like
volatile, const, etc., are removed from the fields in a shadow
type. Function pointers are translated to pointers of struct
bpf_program.

Currently, only scalar types and function pointers are
supported. Fields belonging to structs, unions, non-function pointers,
arrays, or other types are not supported. For those unsupported
fields, they are converted to arrays of characters to preserve their
space within the original struct type.

The padding between consecutive fields is handled by padding fields
(__padding_*). This helps to maintain the memory layout consistent
with the original struct_type.

Here is an example of shadow types.
The origin struct type of a struct_ops map is

    struct bpf_testmod_ops {
    	int (*test_1)(void);
    	void (*test_2)(int a, int b);
    	/* Used to test nullable arguments. */
    	int (*test_maybe_null)(int dummy, struct task_struct *task);
    
    	/* The following fields are used to test shadow copies. */
    	char onebyte;
    	struct {
    		int a;
    		int b;
    	} unsupported;
    	int data;
    };

The struct_ops map, named testmod_1, of this type will be translated
to a pointer in the shadow type.

    struct {
    	struct my_skel_testmod_1_bpf_testmod_ops {
    		const struct bpf_program *test_1;
    		const struct bpf_program *test_2;
    		const struct bpf_program *test_maybe_null;
    		char onebyte;
    		char __padding_4[3];
    		char __unsupported_4[8];
    		int data;
    	} *testmod_1;
    } struct_ops;

== Convert st_ops->data to Shadow Type ==

libbpf converts st_ops->data to the format of the shadow type for each
struct_ops map. This means that the bytes where function pointers are
located are converted to the values of the pointers of struct
bpf_program. The fields of other types are kept as they were.

Libbpf will synchronize the pointers of struct bpf_program with
st_ops->progs[] so that users can change function pointers
(bpf_program) before loading the map.


---
Changes from v5:

 - Generate names for shadow types.

 - Check btf and the number of struct_ops maps in gen_st_ops_shadow()
   and gen_st_ops_shadow_init() instead of do_skeleton() and
   do_subskeleton().

 - Name unsupported fields in the pattern __unsupported_*.

 - Have a padding field for a unsupported fields as well if necessary.

 - Implement resolve_func_ptr() in gen.c instead of reusing the one in
   libbpf. (Remove the part 1 in v4.)

 - Fix stylistic issues.

Changes from v4:

 - Convert function pointers to the pointers to struct bpf_program in
   bpf_object__collect_st_ops_relos().

Changes from v3:

 - Add comment to avoid people from removing resolve_func_ptr() from
   libbpf_internal.h

 - Fix commit logs and comments.

 - Add an example about using the pointers of shadow types
   for struct_ops maps to bpftool-gen.8.

v5: https://lore.kernel.org/all/20240227010432.714127-1-thinker.li@gmail.com/
v4: https://lore.kernel.org/all/20240222222624.1163754-1-thinker.li@gmail.com/
v3: https://lore.kernel.org/all/20240221012329.1387275-1-thinker.li@gmail.com/
v2: https://lore.kernel.org/all/20240214020836.1845354-1-thinker.li@gmail.com/
v1: https://lore.kernel.org/all/20240124224130.859921-1-thinker.li@gmail.com/

Kui-Feng Lee (5):
  libbpf: set btf_value_type_id of struct bpf_map for struct_ops.
  libbpf: Convert st_ops->data to shadow type.
  bpftool: generated shadow variables for struct_ops maps.
  bpftool: Add an example for struct_ops map and shadow type.
  selftests/bpf: Test if shadow types work correctly.

 .../bpf/bpftool/Documentation/bpftool-gen.rst |  58 ++++-
 tools/bpf/bpftool/gen.c                       | 237 +++++++++++++++++-
 tools/lib/bpf/libbpf.c                        |  50 +++-
 .../selftests/bpf/bpf_testmod/bpf_testmod.c   |  11 +-
 .../selftests/bpf/bpf_testmod/bpf_testmod.h   |   8 +
 .../bpf/prog_tests/test_struct_ops_module.c   |  19 +-
 .../selftests/bpf/progs/struct_ops_module.c   |   8 +
 7 files changed, 377 insertions(+), 14 deletions(-)

Comments

patchwork-bot+netdevbpf@kernel.org Feb. 29, 2024, 10:30 p.m. UTC | #1
Hello:

This series was applied to bpf/bpf-next.git (master)
by Andrii Nakryiko <andrii@kernel.org>:

On Wed, 28 Feb 2024 22:45:18 -0800 you wrote:
> This patchset allows skeleton users to change the values of the fields
> in struct_ops maps at runtime. It will create a shadow type pointer in
> a skeleton for each struct_ops map, allowing users to access the
> values of fields through these pointers. For instance, if there is an
> integer field named "FOO" in a struct_ops map called "testmap", you
> can access the value of "FOO" in this way.
> 
> [...]

Here is the summary with links:
  - [bpf-next,v6,1/5] libbpf: set btf_value_type_id of struct bpf_map for struct_ops.
    https://git.kernel.org/bpf/bpf-next/c/3644d285462a
  - [bpf-next,v6,2/5] libbpf: Convert st_ops->data to shadow type.
    https://git.kernel.org/bpf/bpf-next/c/69e4a9d2b3f5
  - [bpf-next,v6,3/5] bpftool: generated shadow variables for struct_ops maps.
    https://git.kernel.org/bpf/bpf-next/c/a7b0fa352eaf
  - [bpf-next,v6,4/5] bpftool: Add an example for struct_ops map and shadow type.
    https://git.kernel.org/bpf/bpf-next/c/f2e81192e07e
  - [bpf-next,v6,5/5] selftests/bpf: Test if shadow types work correctly.
    https://git.kernel.org/bpf/bpf-next/c/0623e7331794

You are awesome, thank you!