Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arch/x86/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3164,7 +3164,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im

/* extra registers for struct arguments */
for (i = 0; i < m->nr_args; i++) {
if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG)
if (m->arg_flags[i] & (BTF_FMODEL_STRUCT_ARG | BTF_FMODEL_UNION_ARG))
nr_regs += (m->arg_size[i] + 7) / 8 - 1;
}

Expand Down
3 changes: 3 additions & 0 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,9 @@ struct bpf_prog_offload {
/* The argument is signed. */
#define BTF_FMODEL_SIGNED_ARG BIT(1)

/* The argument is a union. */
#define BTF_FMODEL_UNION_ARG BIT(2)

struct btf_func_model {
u8 ret_size;
u8 ret_flags;
Expand Down
5 changes: 5 additions & 0 deletions include/linux/btf.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ static inline bool btf_type_is_struct(const struct btf_type *t)
return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
}

static inline bool __btf_type_is_union(const struct btf_type *t)
{
return BTF_INFO_KIND(t->info) == BTF_KIND_UNION;
}

static inline bool __btf_type_is_struct(const struct btf_type *t)
{
return BTF_INFO_KIND(t->info) == BTF_KIND_STRUCT;
Expand Down
8 changes: 5 additions & 3 deletions kernel/bpf/btf.c
Original file line number Diff line number Diff line change
Expand Up @@ -6762,7 +6762,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
/* skip modifiers */
while (btf_type_is_modifier(t))
t = btf_type_by_id(btf, t->type);
if (btf_type_is_small_int(t) || btf_is_any_enum(t) || __btf_type_is_struct(t))
if (btf_type_is_small_int(t) || btf_is_any_enum(t) || btf_type_is_struct(t))
/* accessing a scalar */
return true;
if (!btf_type_is_ptr(t)) {
Expand Down Expand Up @@ -7334,7 +7334,7 @@ static int __get_type_size(struct btf *btf, u32 btf_id,
if (btf_type_is_ptr(t))
/* kernel size of pointer. Not BPF's size of pointer*/
return sizeof(void *);
if (btf_type_is_int(t) || btf_is_any_enum(t) || __btf_type_is_struct(t))
if (btf_type_is_int(t) || btf_is_any_enum(t) || btf_type_is_struct(t))
return t->size;
return -EINVAL;
}
Expand All @@ -7347,6 +7347,8 @@ static u8 __get_type_fmodel_flags(const struct btf_type *t)
flags |= BTF_FMODEL_STRUCT_ARG;
if (btf_type_is_signed_int(t))
flags |= BTF_FMODEL_SIGNED_ARG;
if (__btf_type_is_union(t))
flags |= BTF_FMODEL_UNION_ARG;

return flags;
}
Expand Down Expand Up @@ -7384,7 +7386,7 @@ int btf_distill_func_proto(struct bpf_verifier_log *log,
return -EINVAL;
}
ret = __get_type_size(btf, func->type, &t);
if (ret < 0 || __btf_type_is_struct(t)) {
if (ret < 0 || btf_type_is_struct(t)) {
bpf_log(log,
"The function %s return type %s is unsupported.\n",
tname, btf_type_str(t));
Expand Down
29 changes: 29 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/tracing_struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,39 @@ static void test_struct_many_args(void)
tracing_struct_many_args__destroy(skel);
}

static void test_union_args(void)
{
struct tracing_struct *skel;
int err;

skel = tracing_struct__open_and_load();
if (!ASSERT_OK_PTR(skel, "tracing_struct__open_and_load"))
return;

err = tracing_struct__attach(skel);
if (!ASSERT_OK(err, "tracing_struct__attach"))
goto out;

ASSERT_OK(trigger_module_test_read(256), "trigger_read");

ASSERT_EQ(skel->bss->ut1_a_a, 1, "ut1:a.arg.a");
ASSERT_EQ(skel->bss->ut1_b, 4, "ut1:b");
ASSERT_EQ(skel->bss->ut1_c, 5, "ut1:c");

ASSERT_EQ(skel->bss->ut2_a, 6, "ut2:a");
ASSERT_EQ(skel->bss->ut2_b_a, 2, "ut2:b.arg.a");
ASSERT_EQ(skel->bss->ut2_b_b, 3, "ut2:b.arg.b");

out:
tracing_struct__destroy(skel);
}

void test_tracing_struct(void)
{
if (test__start_subtest("struct_args"))
test_struct_args();
if (test__start_subtest("struct_many_args"))
test_struct_many_args();
if (test__start_subtest("union_args"))
test_union_args();
}
33 changes: 33 additions & 0 deletions tools/testing/selftests/bpf/progs/tracing_struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ struct bpf_testmod_struct_arg_3 {
int b[];
};

union bpf_testmod_union_arg_1 {
char a;
short b;
struct bpf_testmod_struct_arg_1 arg;
};

union bpf_testmod_union_arg_2 {
int a;
long b;
struct bpf_testmod_struct_arg_2 arg;
};

long t1_a_a, t1_a_b, t1_b, t1_c, t1_ret, t1_nregs;
__u64 t1_reg0, t1_reg1, t1_reg2, t1_reg3;
long t2_a, t2_b_a, t2_b_b, t2_c, t2_ret;
Expand All @@ -26,6 +38,9 @@ long t4_a_a, t4_b, t4_c, t4_d, t4_e_a, t4_e_b, t4_ret;
long t5_ret;
int t6;

long ut1_a_a, ut1_b, ut1_c;
long ut2_a, ut2_b_a, ut2_b_b;

SEC("fentry/bpf_testmod_test_struct_arg_1")
int BPF_PROG2(test_struct_arg_1, struct bpf_testmod_struct_arg_2, a, int, b, int, c)
{
Expand Down Expand Up @@ -130,4 +145,22 @@ int BPF_PROG2(test_struct_arg_11, struct bpf_testmod_struct_arg_3 *, a)
return 0;
}

SEC("fexit/bpf_testmod_test_union_arg_1")
int BPF_PROG2(test_union_arg_1, union bpf_testmod_union_arg_1, a, int, b, int, c)
{
ut1_a_a = a.arg.a;
ut1_b = b;
ut1_c = c;
return 0;
}

SEC("fexit/bpf_testmod_test_union_arg_2")
int BPF_PROG2(test_union_arg_2, int, a, union bpf_testmod_union_arg_2, b)
{
ut2_a = a;
ut2_b_a = b.arg.a;
ut2_b_b = b.arg.b;
return 0;
}

char _license[] SEC("license") = "GPL";
31 changes: 31 additions & 0 deletions tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ struct bpf_testmod_struct_arg_5 {
long d;
};

union bpf_testmod_union_arg_1 {
char a;
short b;
struct bpf_testmod_struct_arg_1 arg;
};

union bpf_testmod_union_arg_2 {
int a;
long b;
struct bpf_testmod_struct_arg_2 arg;
};

__bpf_hook_start();

noinline int
Expand Down Expand Up @@ -128,6 +140,20 @@ bpf_testmod_test_struct_arg_9(u64 a, void *b, short c, int d, void *e, char f,
return bpf_testmod_test_struct_arg_result;
}

noinline int
bpf_testmod_test_union_arg_1(union bpf_testmod_union_arg_1 a, int b, int c)
{
bpf_testmod_test_struct_arg_result = a.arg.a + b + c;
return bpf_testmod_test_struct_arg_result;
}

noinline int
bpf_testmod_test_union_arg_2(int a, union bpf_testmod_union_arg_2 b)
{
bpf_testmod_test_struct_arg_result = a + b.arg.a + b.arg.b;
return bpf_testmod_test_struct_arg_result;
}

noinline int
bpf_testmod_test_arg_ptr_to_struct(struct bpf_testmod_struct_arg_1 *a) {
bpf_testmod_test_struct_arg_result = a->a;
Expand Down Expand Up @@ -398,6 +424,8 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
struct bpf_testmod_struct_arg_3 *struct_arg3;
struct bpf_testmod_struct_arg_4 struct_arg4 = {21, 22};
struct bpf_testmod_struct_arg_5 struct_arg5 = {23, 24, 25, 26};
union bpf_testmod_union_arg_1 union_arg1 = { .arg = {1} };
union bpf_testmod_union_arg_2 union_arg2 = { .arg = {2, 3} };
int i = 1;

while (bpf_testmod_return_ptr(i))
Expand All @@ -415,6 +443,9 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
(void)bpf_testmod_test_struct_arg_9(16, (void *)17, 18, 19, (void *)20,
21, 22, struct_arg5, 27);

(void)bpf_testmod_test_union_arg_1(union_arg1, 4, 5);
(void)bpf_testmod_test_union_arg_2(6, union_arg2);

(void)bpf_testmod_test_arg_ptr_to_struct(&struct_arg1_2);

(void)trace_bpf_testmod_test_raw_tp_null_tp(NULL);
Expand Down
Loading