* [PATCH bpf-next v5 01/10] bpf: add fsession support
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2026-01-01 13:52 ` Jiri Olsa
2025-12-24 13:07 ` [PATCH bpf-next v5 02/10] bpf: use last 8-bits for the nr_args in trampoline Menglong Dong
` (8 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
The fsession is something that similar to kprobe session. It allow to
attach a single BPF program to both the entry and the exit of the target
functions.
Introduce the struct bpf_fsession_link, which allows to add the link to
both the fentry and fexit progs_hlist of the trampoline.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
Co-developed-by: Leon Hwang <leon.hwang@linux.dev>
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
v5:
- unify the name to "fsession"
- use more explicit way in __bpf_trampoline_link_prog()
v4:
- instead of adding a new hlist to progs_hlist in trampoline, add the bpf
program to both the fentry hlist and the fexit hlist.
---
include/linux/bpf.h | 20 ++++++++++
include/uapi/linux/bpf.h | 1 +
kernel/bpf/btf.c | 2 +
kernel/bpf/syscall.c | 18 ++++++++-
kernel/bpf/trampoline.c | 40 ++++++++++++++++---
kernel/bpf/verifier.c | 12 ++++--
net/bpf/test_run.c | 1 +
net/core/bpf_sk_storage.c | 1 +
tools/include/uapi/linux/bpf.h | 1 +
.../bpf/prog_tests/tracing_failure.c | 2 +-
10 files changed, 88 insertions(+), 10 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 28d8d6b7bb1e..63e1bc29485e 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1291,6 +1291,7 @@ enum bpf_tramp_prog_type {
BPF_TRAMP_MODIFY_RETURN,
BPF_TRAMP_MAX,
BPF_TRAMP_REPLACE, /* more than MAX */
+ BPF_TRAMP_FSESSION,
};
struct bpf_tramp_image {
@@ -1854,6 +1855,11 @@ struct bpf_tracing_link {
struct bpf_prog *tgt_prog;
};
+struct bpf_fsession_link {
+ struct bpf_tracing_link link;
+ struct bpf_tramp_link fexit;
+};
+
struct bpf_raw_tp_link {
struct bpf_link link;
struct bpf_raw_event_map *btp;
@@ -2114,6 +2120,20 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
#endif
+static inline int bpf_fsession_cnt(struct bpf_tramp_links *links)
+{
+ struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY];
+ int cnt = 0;
+
+ for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) {
+ if (fentries.links[i]->link.prog->expected_attach_type ==
+ BPF_TRACE_FSESSION)
+ cnt++;
+ }
+
+ return cnt;
+}
+
int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
const struct bpf_ctx_arg_aux *info, u32 cnt);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 84ced3ed2d21..cd2d7c4fc6e7 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1145,6 +1145,7 @@ enum bpf_attach_type {
BPF_NETKIT_PEER,
BPF_TRACE_KPROBE_SESSION,
BPF_TRACE_UPROBE_SESSION,
+ BPF_TRACE_FSESSION,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 0de8fc8a0e0b..dff3eae4b51e 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6107,6 +6107,7 @@ static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
case BPF_MODIFY_RETURN:
+ case BPF_TRACE_FSESSION:
/* allow u64* as ctx */
if (btf_is_int(t) && t->size == 8)
return 0;
@@ -6704,6 +6705,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
fallthrough;
case BPF_LSM_CGROUP:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
/* When LSM programs are attached to void LSM hooks
* they use FEXIT trampolines and when attached to
* int LSM hooks, they use MODIFY_RETURN trampolines.
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 3080cc48bfc3..3bfaf550ad08 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3579,6 +3579,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
case BPF_PROG_TYPE_TRACING:
if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
prog->expected_attach_type != BPF_TRACE_FEXIT &&
+ prog->expected_attach_type != BPF_TRACE_FSESSION &&
prog->expected_attach_type != BPF_MODIFY_RETURN) {
err = -EINVAL;
goto out_put_prog;
@@ -3628,7 +3629,21 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
}
- link = kzalloc(sizeof(*link), GFP_USER);
+ if (prog->expected_attach_type == BPF_TRACE_FSESSION) {
+ struct bpf_fsession_link *fslink;
+
+ fslink = kzalloc(sizeof(*fslink), GFP_USER);
+ if (fslink) {
+ bpf_link_init(&fslink->fexit.link, BPF_LINK_TYPE_TRACING,
+ &bpf_tracing_link_lops, prog, attach_type);
+ fslink->fexit.cookie = bpf_cookie;
+ link = &fslink->link;
+ } else {
+ link = NULL;
+ }
+ } else {
+ link = kzalloc(sizeof(*link), GFP_USER);
+ }
if (!link) {
err = -ENOMEM;
goto out_put_prog;
@@ -4352,6 +4367,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
case BPF_TRACE_RAW_TP:
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
case BPF_MODIFY_RETURN:
return BPF_PROG_TYPE_TRACING;
case BPF_LSM_MAC:
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 976d89011b15..77d474fc973a 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -111,7 +111,7 @@ bool bpf_prog_has_trampoline(const struct bpf_prog *prog)
return (ptype == BPF_PROG_TYPE_TRACING &&
(eatype == BPF_TRACE_FENTRY || eatype == BPF_TRACE_FEXIT ||
- eatype == BPF_MODIFY_RETURN)) ||
+ eatype == BPF_MODIFY_RETURN || eatype == BPF_TRACE_FSESSION)) ||
(ptype == BPF_PROG_TYPE_LSM && eatype == BPF_LSM_MAC);
}
@@ -559,6 +559,8 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)
return BPF_TRAMP_MODIFY_RETURN;
case BPF_TRACE_FEXIT:
return BPF_TRAMP_FEXIT;
+ case BPF_TRACE_FSESSION:
+ return BPF_TRAMP_FSESSION;
case BPF_LSM_MAC:
if (!prog->aux->attach_func_proto->type)
/* The function returns void, we cannot modify its
@@ -596,6 +598,8 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
{
enum bpf_tramp_prog_type kind;
struct bpf_tramp_link *link_exiting;
+ struct bpf_fsession_link *fslink;
+ struct hlist_head *prog_list;
int err = 0;
int cnt = 0, i;
@@ -621,24 +625,44 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
BPF_MOD_JUMP, NULL,
link->link.prog->bpf_func);
}
+ if (kind == BPF_TRAMP_FSESSION) {
+ prog_list = &tr->progs_hlist[BPF_TRAMP_FENTRY];
+ cnt++;
+ } else {
+ prog_list = &tr->progs_hlist[kind];
+ }
if (cnt >= BPF_MAX_TRAMP_LINKS)
return -E2BIG;
if (!hlist_unhashed(&link->tramp_hlist))
/* prog already linked */
return -EBUSY;
- hlist_for_each_entry(link_exiting, &tr->progs_hlist[kind], tramp_hlist) {
+ hlist_for_each_entry(link_exiting, prog_list, tramp_hlist) {
if (link_exiting->link.prog != link->link.prog)
continue;
/* prog already linked */
return -EBUSY;
}
- hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]);
- tr->progs_cnt[kind]++;
+ hlist_add_head(&link->tramp_hlist, prog_list);
+ if (kind == BPF_TRAMP_FSESSION) {
+ tr->progs_cnt[BPF_TRAMP_FENTRY]++;
+ fslink = container_of(link, struct bpf_fsession_link, link.link);
+ hlist_add_head(&fslink->fexit.tramp_hlist,
+ &tr->progs_hlist[BPF_TRAMP_FEXIT]);
+ tr->progs_cnt[BPF_TRAMP_FEXIT]++;
+ } else {
+ tr->progs_cnt[kind]++;
+ }
err = bpf_trampoline_update(tr, true /* lock_direct_mutex */);
if (err) {
hlist_del_init(&link->tramp_hlist);
- tr->progs_cnt[kind]--;
+ if (kind == BPF_TRAMP_FSESSION) {
+ tr->progs_cnt[BPF_TRAMP_FENTRY]--;
+ hlist_del_init(&fslink->fexit.tramp_hlist);
+ tr->progs_cnt[BPF_TRAMP_FEXIT]--;
+ } else {
+ tr->progs_cnt[kind]--;
+ }
}
return err;
}
@@ -659,6 +683,7 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
struct bpf_trampoline *tr,
struct bpf_prog *tgt_prog)
{
+ struct bpf_fsession_link *fslink;
enum bpf_tramp_prog_type kind;
int err;
@@ -672,6 +697,11 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
guard(mutex)(&tgt_prog->aux->ext_mutex);
tgt_prog->aux->is_extended = false;
return err;
+ } else if (kind == BPF_TRAMP_FSESSION) {
+ fslink = container_of(link, struct bpf_fsession_link, link.link);
+ hlist_del_init(&fslink->fexit.tramp_hlist);
+ tr->progs_cnt[BPF_TRAMP_FEXIT]--;
+ kind = BPF_TRAMP_FENTRY;
}
hlist_del_init(&link->tramp_hlist);
tr->progs_cnt[kind]--;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a31c032b2dd6..b9714a7c3c5f 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -17402,6 +17402,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char
switch (env->prog->expected_attach_type) {
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
range = retval_range(0, 0);
break;
case BPF_TRACE_RAW_TP:
@@ -23298,6 +23299,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
if (prog_type == BPF_PROG_TYPE_TRACING &&
insn->imm == BPF_FUNC_get_func_ret) {
if (eatype == BPF_TRACE_FEXIT ||
+ eatype == BPF_TRACE_FSESSION ||
eatype == BPF_MODIFY_RETURN) {
/* Load nr_args from ctx - 8 */
insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
@@ -24242,7 +24244,8 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
if (tgt_prog->type == BPF_PROG_TYPE_TRACING &&
prog_extension &&
(tgt_prog->expected_attach_type == BPF_TRACE_FENTRY ||
- tgt_prog->expected_attach_type == BPF_TRACE_FEXIT)) {
+ tgt_prog->expected_attach_type == BPF_TRACE_FEXIT ||
+ tgt_prog->expected_attach_type == BPF_TRACE_FSESSION)) {
/* Program extensions can extend all program types
* except fentry/fexit. The reason is the following.
* The fentry/fexit programs are used for performance
@@ -24257,7 +24260,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
* beyond reasonable stack size. Hence extending fentry
* is not allowed.
*/
- bpf_log(log, "Cannot extend fentry/fexit\n");
+ bpf_log(log, "Cannot extend fentry/fexit/fsession\n");
return -EINVAL;
}
} else {
@@ -24341,6 +24344,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
case BPF_LSM_CGROUP:
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
if (!btf_type_is_func(t)) {
bpf_log(log, "attach_btf_id %u is not a function\n",
btf_id);
@@ -24507,6 +24511,7 @@ static bool can_be_sleepable(struct bpf_prog *prog)
case BPF_TRACE_FEXIT:
case BPF_MODIFY_RETURN:
case BPF_TRACE_ITER:
+ case BPF_TRACE_FSESSION:
return true;
default:
return false;
@@ -24588,9 +24593,10 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
tgt_info.tgt_name);
return -EINVAL;
} else if ((prog->expected_attach_type == BPF_TRACE_FEXIT ||
+ prog->expected_attach_type == BPF_TRACE_FSESSION ||
prog->expected_attach_type == BPF_MODIFY_RETURN) &&
btf_id_set_contains(&noreturn_deny, btf_id)) {
- verbose(env, "Attaching fexit/fmod_ret to __noreturn function '%s' is rejected.\n",
+ verbose(env, "Attaching fexit/fsession/fmod_ret to __noreturn function '%s' is rejected.\n",
tgt_info.tgt_name);
return -EINVAL;
}
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 655efac6f133..3b0d9bd039de 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -685,6 +685,7 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
switch (prog->expected_attach_type) {
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
if (bpf_fentry_test1(1) != 2 ||
bpf_fentry_test2(2, 3) != 5 ||
bpf_fentry_test3(4, 5, 6) != 15 ||
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 850dd736ccd1..de111818f3a0 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -365,6 +365,7 @@ static bool bpf_sk_storage_tracing_allowed(const struct bpf_prog *prog)
return true;
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
return !!strncmp(prog->aux->attach_func_name, "bpf_sk_storage",
strlen("bpf_sk_storage"));
default:
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 6b92b0847ec2..012abaf3d4ac 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1145,6 +1145,7 @@ enum bpf_attach_type {
BPF_NETKIT_PEER,
BPF_TRACE_KPROBE_SESSION,
BPF_TRACE_UPROBE_SESSION,
+ BPF_TRACE_FSESSION,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c
index 10e231965589..f9f9e1cb87bf 100644
--- a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c
+++ b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c
@@ -73,7 +73,7 @@ static void test_tracing_deny(void)
static void test_fexit_noreturns(void)
{
test_tracing_fail_prog("fexit_noreturns",
- "Attaching fexit/fmod_ret to __noreturn function 'do_exit' is rejected.");
+ "Attaching fexit/fsession/fmod_ret to __noreturn function 'do_exit' is rejected.");
}
void test_tracing_failure(void)
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH bpf-next v5 01/10] bpf: add fsession support
2025-12-24 13:07 ` [PATCH bpf-next v5 01/10] bpf: add " Menglong Dong
@ 2026-01-01 13:52 ` Jiri Olsa
2026-01-02 9:21 ` Menglong Dong
0 siblings, 1 reply; 14+ messages in thread
From: Jiri Olsa @ 2026-01-01 13:52 UTC (permalink / raw)
To: Menglong Dong
Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
john.fastabend, kpsingh, sdf, haoluo, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
On Wed, Dec 24, 2025 at 09:07:26PM +0800, Menglong Dong wrote:
SNIP
> +struct bpf_fsession_link {
> + struct bpf_tracing_link link;
> + struct bpf_tramp_link fexit;
> +};
> +
> struct bpf_raw_tp_link {
> struct bpf_link link;
> struct bpf_raw_event_map *btp;
> @@ -2114,6 +2120,20 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
>
> #endif
>
> +static inline int bpf_fsession_cnt(struct bpf_tramp_links *links)
> +{
> + struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY];
> + int cnt = 0;
> +
> + for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) {
> + if (fentries.links[i]->link.prog->expected_attach_type ==
> + BPF_TRACE_FSESSION)
let's keep it on the single line ?
> + cnt++;
> + }
> +
> + return cnt;
> +}
> +
> int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
> const struct bpf_ctx_arg_aux *info, u32 cnt);
>
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 84ced3ed2d21..cd2d7c4fc6e7 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -1145,6 +1145,7 @@ enum bpf_attach_type {
> BPF_NETKIT_PEER,
> BPF_TRACE_KPROBE_SESSION,
> BPF_TRACE_UPROBE_SESSION,
> + BPF_TRACE_FSESSION,
> __MAX_BPF_ATTACH_TYPE
> };
>
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 0de8fc8a0e0b..dff3eae4b51e 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -6107,6 +6107,7 @@ static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct
> case BPF_TRACE_FENTRY:
> case BPF_TRACE_FEXIT:
> case BPF_MODIFY_RETURN:
> + case BPF_TRACE_FSESSION:
> /* allow u64* as ctx */
> if (btf_is_int(t) && t->size == 8)
> return 0;
> @@ -6704,6 +6705,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
> fallthrough;
> case BPF_LSM_CGROUP:
> case BPF_TRACE_FEXIT:
> + case BPF_TRACE_FSESSION:
> /* When LSM programs are attached to void LSM hooks
> * they use FEXIT trampolines and when attached to
> * int LSM hooks, they use MODIFY_RETURN trampolines.
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 3080cc48bfc3..3bfaf550ad08 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -3579,6 +3579,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
> case BPF_PROG_TYPE_TRACING:
> if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
> prog->expected_attach_type != BPF_TRACE_FEXIT &&
> + prog->expected_attach_type != BPF_TRACE_FSESSION &&
> prog->expected_attach_type != BPF_MODIFY_RETURN) {
> err = -EINVAL;
> goto out_put_prog;
> @@ -3628,7 +3629,21 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
> key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
> }
>
> - link = kzalloc(sizeof(*link), GFP_USER);
> + if (prog->expected_attach_type == BPF_TRACE_FSESSION) {
> + struct bpf_fsession_link *fslink;
> +
> + fslink = kzalloc(sizeof(*fslink), GFP_USER);
> + if (fslink) {
> + bpf_link_init(&fslink->fexit.link, BPF_LINK_TYPE_TRACING,
> + &bpf_tracing_link_lops, prog, attach_type);
I don't think we need the extra exit struct bpf_link, we just need
hlist_node hook for exit program, so this should perhaps be:
struct bpf_fsession_link {
struct bpf_tracing_link link;
struct hlist_node tramp_hlist;
};
SNIP
> @@ -596,6 +598,8 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
> {
> enum bpf_tramp_prog_type kind;
> struct bpf_tramp_link *link_exiting;
> + struct bpf_fsession_link *fslink;
> + struct hlist_head *prog_list;
> int err = 0;
> int cnt = 0, i;
>
> @@ -621,24 +625,44 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
> BPF_MOD_JUMP, NULL,
> link->link.prog->bpf_func);
> }
> + if (kind == BPF_TRAMP_FSESSION) {
> + prog_list = &tr->progs_hlist[BPF_TRAMP_FENTRY];
> + cnt++;
> + } else {
> + prog_list = &tr->progs_hlist[kind];
> + }
> if (cnt >= BPF_MAX_TRAMP_LINKS)
> return -E2BIG;
> if (!hlist_unhashed(&link->tramp_hlist))
> /* prog already linked */
> return -EBUSY;
> - hlist_for_each_entry(link_exiting, &tr->progs_hlist[kind], tramp_hlist) {
> + hlist_for_each_entry(link_exiting, prog_list, tramp_hlist) {
> if (link_exiting->link.prog != link->link.prog)
> continue;
> /* prog already linked */
> return -EBUSY;
> }
>
> - hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]);
> - tr->progs_cnt[kind]++;
> + hlist_add_head(&link->tramp_hlist, prog_list);
> + if (kind == BPF_TRAMP_FSESSION) {
> + tr->progs_cnt[BPF_TRAMP_FENTRY]++;
> + fslink = container_of(link, struct bpf_fsession_link, link.link);
> + hlist_add_head(&fslink->fexit.tramp_hlist,
> + &tr->progs_hlist[BPF_TRAMP_FEXIT]);
> + tr->progs_cnt[BPF_TRAMP_FEXIT]++;
> + } else {
> + tr->progs_cnt[kind]++;
> + }
> err = bpf_trampoline_update(tr, true /* lock_direct_mutex */);
> if (err) {
> hlist_del_init(&link->tramp_hlist);
> - tr->progs_cnt[kind]--;
> + if (kind == BPF_TRAMP_FSESSION) {
> + tr->progs_cnt[BPF_TRAMP_FENTRY]--;
> + hlist_del_init(&fslink->fexit.tramp_hlist);
> + tr->progs_cnt[BPF_TRAMP_FEXIT]--;
> + } else {
> + tr->progs_cnt[kind]--;
> + }
> }
> return err;
this seems confusing, how about we just add abolish bpf_fsession_link
and add extra hlist_node hook to struct bpf_tramp_link .. we will waste
16 bytes for other cases, but the code seems less confusing to me
untested, so I might overlooked something..
jirka
---
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 4e7d72dfbcd4..7479664844ea 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1309,6 +1309,7 @@ enum bpf_tramp_prog_type {
BPF_TRAMP_MODIFY_RETURN,
BPF_TRAMP_MAX,
BPF_TRAMP_REPLACE, /* more than MAX */
+ BPF_TRAMP_FSESSION,
};
struct bpf_tramp_image {
@@ -1861,6 +1862,7 @@ struct bpf_link_ops {
struct bpf_tramp_link {
struct bpf_link link;
struct hlist_node tramp_hlist;
+ struct hlist_node extra_hlist;
u64 cookie;
};
@@ -2169,6 +2171,19 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
#endif
+static inline int bpf_fsession_cnt(struct bpf_tramp_links *links)
+{
+ struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY];
+ int cnt = 0;
+
+ for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) {
+ if (fentries.links[i]->link.prog->expected_attach_type == BPF_TRACE_FSESSION)
+ cnt++;
+ }
+
+ return cnt;
+}
+
int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
const struct bpf_ctx_arg_aux *info, u32 cnt);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 84ced3ed2d21..cd2d7c4fc6e7 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1145,6 +1145,7 @@ enum bpf_attach_type {
BPF_NETKIT_PEER,
BPF_TRACE_KPROBE_SESSION,
BPF_TRACE_UPROBE_SESSION,
+ BPF_TRACE_FSESSION,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 539c9fdea41d..8b1dcd440356 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6107,6 +6107,7 @@ static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
case BPF_MODIFY_RETURN:
+ case BPF_TRACE_FSESSION:
/* allow u64* as ctx */
if (btf_is_int(t) && t->size == 8)
return 0;
@@ -6704,6 +6705,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
fallthrough;
case BPF_LSM_CGROUP:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
/* When LSM programs are attached to void LSM hooks
* they use FEXIT trampolines and when attached to
* int LSM hooks, they use MODIFY_RETURN trampolines.
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index a4d38272d8bc..d05f59bffa02 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3579,6 +3579,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
case BPF_PROG_TYPE_TRACING:
if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
prog->expected_attach_type != BPF_TRACE_FEXIT &&
+ prog->expected_attach_type != BPF_TRACE_FSESSION &&
prog->expected_attach_type != BPF_MODIFY_RETURN) {
err = -EINVAL;
goto out_put_prog;
@@ -4352,6 +4353,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
case BPF_TRACE_RAW_TP:
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
case BPF_MODIFY_RETURN:
return BPF_PROG_TYPE_TRACING;
case BPF_LSM_MAC:
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 2a125d063e62..f27ed8b934f9 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -111,7 +111,7 @@ bool bpf_prog_has_trampoline(const struct bpf_prog *prog)
return (ptype == BPF_PROG_TYPE_TRACING &&
(eatype == BPF_TRACE_FENTRY || eatype == BPF_TRACE_FEXIT ||
- eatype == BPF_MODIFY_RETURN)) ||
+ eatype == BPF_MODIFY_RETURN || eatype == BPF_TRACE_FSESSION)) ||
(ptype == BPF_PROG_TYPE_LSM && eatype == BPF_LSM_MAC);
}
@@ -559,6 +559,8 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)
return BPF_TRAMP_MODIFY_RETURN;
case BPF_TRACE_FEXIT:
return BPF_TRAMP_FEXIT;
+ case BPF_TRACE_FSESSION:
+ return BPF_TRAMP_FSESSION;
case BPF_LSM_MAC:
if (!prog->aux->attach_func_proto->type)
/* The function returns void, we cannot modify its
@@ -621,6 +623,8 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
BPF_MOD_JUMP, NULL,
link->link.prog->bpf_func);
}
+ if (kind == BPF_TRAMP_FSESSION)
+ cnt++;
if (cnt >= BPF_MAX_TRAMP_LINKS)
return -E2BIG;
if (!hlist_unhashed(&link->tramp_hlist))
@@ -633,12 +637,27 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
return -EBUSY;
}
- hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]);
- tr->progs_cnt[kind]++;
+ if (kind == BPF_TRAMP_FSESSION) {
+ hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[BPF_TRAMP_FENTRY]);
+ hlist_add_head(&link->extra_hlist, &tr->progs_hlist[BPF_TRAMP_FEXIT]);
+ tr->progs_cnt[BPF_TRAMP_FENTRY]++;
+ tr->progs_cnt[BPF_TRAMP_FEXIT]++;
+ } else {
+ hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]);
+ tr->progs_cnt[kind]++;
+ }
+
err = bpf_trampoline_update(tr, true /* lock_direct_mutex */);
if (err) {
- hlist_del_init(&link->tramp_hlist);
- tr->progs_cnt[kind]--;
+ if (kind == BPF_TRAMP_FSESSION) {
+ hlist_del_init(&link->tramp_hlist);
+ hlist_del_init(&link->extra_hlist);
+ tr->progs_cnt[BPF_TRAMP_FENTRY]--;
+ tr->progs_cnt[BPF_TRAMP_FEXIT]--;
+ } else {
+ hlist_del_init(&link->tramp_hlist);
+ tr->progs_cnt[kind]--;
+ }
}
return err;
}
@@ -672,9 +691,15 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
guard(mutex)(&tgt_prog->aux->ext_mutex);
tgt_prog->aux->is_extended = false;
return err;
+ } else if (kind == BPF_TRAMP_FSESSION) {
+ hlist_del_init(&link->tramp_hlist);
+ hlist_del_init(&link->extra_hlist);
+ tr->progs_cnt[BPF_TRAMP_FENTRY]--;
+ tr->progs_cnt[BPF_TRAMP_FEXIT]--;
+ } else {
+ hlist_del_init(&link->tramp_hlist);
+ tr->progs_cnt[kind]--;
}
- hlist_del_init(&link->tramp_hlist);
- tr->progs_cnt[kind]--;
return bpf_trampoline_update(tr, true /* lock_direct_mutex */);
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2de1a736ef69..6146f63cb03a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -17406,6 +17406,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char
switch (env->prog->expected_attach_type) {
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
range = retval_range(0, 0);
break;
case BPF_TRACE_RAW_TP:
@@ -23303,6 +23304,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
if (prog_type == BPF_PROG_TYPE_TRACING &&
insn->imm == BPF_FUNC_get_func_ret) {
if (eatype == BPF_TRACE_FEXIT ||
+ eatype == BPF_TRACE_FSESSION ||
eatype == BPF_MODIFY_RETURN) {
/* Load nr_args from ctx - 8 */
insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
@@ -24247,7 +24249,8 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
if (tgt_prog->type == BPF_PROG_TYPE_TRACING &&
prog_extension &&
(tgt_prog->expected_attach_type == BPF_TRACE_FENTRY ||
- tgt_prog->expected_attach_type == BPF_TRACE_FEXIT)) {
+ tgt_prog->expected_attach_type == BPF_TRACE_FEXIT ||
+ tgt_prog->expected_attach_type == BPF_TRACE_FSESSION)) {
/* Program extensions can extend all program types
* except fentry/fexit. The reason is the following.
* The fentry/fexit programs are used for performance
@@ -24262,7 +24265,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
* beyond reasonable stack size. Hence extending fentry
* is not allowed.
*/
- bpf_log(log, "Cannot extend fentry/fexit\n");
+ bpf_log(log, "Cannot extend fentry/fexit/fsession\n");
return -EINVAL;
}
} else {
@@ -24346,6 +24349,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
case BPF_LSM_CGROUP:
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
if (!btf_type_is_func(t)) {
bpf_log(log, "attach_btf_id %u is not a function\n",
btf_id);
@@ -24512,6 +24516,7 @@ static bool can_be_sleepable(struct bpf_prog *prog)
case BPF_TRACE_FEXIT:
case BPF_MODIFY_RETURN:
case BPF_TRACE_ITER:
+ case BPF_TRACE_FSESSION:
return true;
default:
return false;
@@ -24593,9 +24598,10 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
tgt_info.tgt_name);
return -EINVAL;
} else if ((prog->expected_attach_type == BPF_TRACE_FEXIT ||
+ prog->expected_attach_type == BPF_TRACE_FSESSION ||
prog->expected_attach_type == BPF_MODIFY_RETURN) &&
btf_id_set_contains(&noreturn_deny, btf_id)) {
- verbose(env, "Attaching fexit/fmod_ret to __noreturn function '%s' is rejected.\n",
+ verbose(env, "Attaching fexit/fsession/fmod_ret to __noreturn function '%s' is rejected.\n",
tgt_info.tgt_name);
return -EINVAL;
}
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 655efac6f133..3b0d9bd039de 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -685,6 +685,7 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
switch (prog->expected_attach_type) {
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
if (bpf_fentry_test1(1) != 2 ||
bpf_fentry_test2(2, 3) != 5 ||
bpf_fentry_test3(4, 5, 6) != 15 ||
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 850dd736ccd1..de111818f3a0 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -365,6 +365,7 @@ static bool bpf_sk_storage_tracing_allowed(const struct bpf_prog *prog)
return true;
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
+ case BPF_TRACE_FSESSION:
return !!strncmp(prog->aux->attach_func_name, "bpf_sk_storage",
strlen("bpf_sk_storage"));
default:
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 6b92b0847ec2..012abaf3d4ac 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1145,6 +1145,7 @@ enum bpf_attach_type {
BPF_NETKIT_PEER,
BPF_TRACE_KPROBE_SESSION,
BPF_TRACE_UPROBE_SESSION,
+ BPF_TRACE_FSESSION,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c
index 10e231965589..f9f9e1cb87bf 100644
--- a/tools/testing/selftests/bpf/prog_tests/tracing_failure.c
+++ b/tools/testing/selftests/bpf/prog_tests/tracing_failure.c
@@ -73,7 +73,7 @@ static void test_tracing_deny(void)
static void test_fexit_noreturns(void)
{
test_tracing_fail_prog("fexit_noreturns",
- "Attaching fexit/fmod_ret to __noreturn function 'do_exit' is rejected.");
+ "Attaching fexit/fsession/fmod_ret to __noreturn function 'do_exit' is rejected.");
}
void test_tracing_failure(void)
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH bpf-next v5 01/10] bpf: add fsession support
2026-01-01 13:52 ` Jiri Olsa
@ 2026-01-02 9:21 ` Menglong Dong
2026-01-02 12:11 ` Jiri Olsa
0 siblings, 1 reply; 14+ messages in thread
From: Menglong Dong @ 2026-01-02 9:21 UTC (permalink / raw)
To: Menglong Dong, Jiri Olsa
Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
john.fastabend, kpsingh, sdf, haoluo, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
On 2026/1/1 21:52 Jiri Olsa <olsajiri@gmail.com> write:
> On Wed, Dec 24, 2025 at 09:07:26PM +0800, Menglong Dong wrote:
>
> SNIP
Hi, Jiri. Happy New Year!
>
> > +struct bpf_fsession_link {
> > + struct bpf_tracing_link link;
> > + struct bpf_tramp_link fexit;
> > +};
> > +
> > struct bpf_raw_tp_link {
> > struct bpf_link link;
> > struct bpf_raw_event_map *btp;
> > @@ -2114,6 +2120,20 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
> >
> > #endif
> >
> > +static inline int bpf_fsession_cnt(struct bpf_tramp_links *links)
> > +{
> > + struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY];
> > + int cnt = 0;
> > +
> > + for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) {
> > + if (fentries.links[i]->link.prog->expected_attach_type ==
> > + BPF_TRACE_FSESSION)
>
> let's keep it on the single line ?
OK
>
> > + cnt++;
> > + }
> > +
> > + return cnt;
> > +}
> > +
[......]
> > @@ -3628,7 +3629,21 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
> > key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
> > }
> >
> > - link = kzalloc(sizeof(*link), GFP_USER);
> > + if (prog->expected_attach_type == BPF_TRACE_FSESSION) {
> > + struct bpf_fsession_link *fslink;
> > +
> > + fslink = kzalloc(sizeof(*fslink), GFP_USER);
> > + if (fslink) {
> > + bpf_link_init(&fslink->fexit.link, BPF_LINK_TYPE_TRACING,
> > + &bpf_tracing_link_lops, prog, attach_type);
>
> I don't think we need the extra exit struct bpf_link, we just need
> hlist_node hook for exit program, so this should perhaps be:
>
> struct bpf_fsession_link {
> struct bpf_tracing_link link;
> struct hlist_node tramp_hlist;
> };
I think we can't do it this way according to how we manager
the bpf_link in trampoline, as you can see in
bpf_trampoline_get_progs() and the struct of bpf_tramp_links.
In bpf_trampoline_get_progs(), it will lookup all the bpf_link
in the trampoline. If we simply add the bpf_fsession_link->tramp_hlist,
the struct in the progs_hlist will be inconsistent.
>
>
> SNIP
>
> > @@ -596,6 +598,8 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
> > {
> > enum bpf_tramp_prog_type kind;
> > struct bpf_tramp_link *link_exiting;
> > + struct bpf_fsession_link *fslink;
> > + struct hlist_head *prog_list;
> > int err = 0;
> > int cnt = 0, i;
> >
> > @@ -621,24 +625,44 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
> > BPF_MOD_JUMP, NULL,
> > link->link.prog->bpf_func);
> > }
> > + if (kind == BPF_TRAMP_FSESSION) {
> > + prog_list = &tr->progs_hlist[BPF_TRAMP_FENTRY];
> > + cnt++;
> > + } else {
> > + prog_list = &tr->progs_hlist[kind];
> > + }
> > if (cnt >= BPF_MAX_TRAMP_LINKS)
> > return -E2BIG;
> > if (!hlist_unhashed(&link->tramp_hlist))
> > /* prog already linked */
> > return -EBUSY;
> > - hlist_for_each_entry(link_exiting, &tr->progs_hlist[kind], tramp_hlist) {
> > + hlist_for_each_entry(link_exiting, prog_list, tramp_hlist) {
> > if (link_exiting->link.prog != link->link.prog)
> > continue;
> > /* prog already linked */
> > return -EBUSY;
> > }
> >
> > - hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]);
> > - tr->progs_cnt[kind]++;
> > + hlist_add_head(&link->tramp_hlist, prog_list);
> > + if (kind == BPF_TRAMP_FSESSION) {
> > + tr->progs_cnt[BPF_TRAMP_FENTRY]++;
> > + fslink = container_of(link, struct bpf_fsession_link, link.link);
> > + hlist_add_head(&fslink->fexit.tramp_hlist,
> > + &tr->progs_hlist[BPF_TRAMP_FEXIT]);
> > + tr->progs_cnt[BPF_TRAMP_FEXIT]++;
> > + } else {
> > + tr->progs_cnt[kind]++;
> > + }
> > err = bpf_trampoline_update(tr, true /* lock_direct_mutex */);
> > if (err) {
> > hlist_del_init(&link->tramp_hlist);
> > - tr->progs_cnt[kind]--;
> > + if (kind == BPF_TRAMP_FSESSION) {
> > + tr->progs_cnt[BPF_TRAMP_FENTRY]--;
> > + hlist_del_init(&fslink->fexit.tramp_hlist);
> > + tr->progs_cnt[BPF_TRAMP_FEXIT]--;
> > + } else {
> > + tr->progs_cnt[kind]--;
> > + }
> > }
> > return err;
>
> this seems confusing, how about we just add abolish bpf_fsession_link
It was more confusing in V1. I adopted Andrii's suggestion in
this version to make the logic here more clear. But it seems
still confusing :/
Maybe we need more document here to help the understanding.
> and add extra hlist_node hook to struct bpf_tramp_link .. we will waste
> 16 bytes for other cases, but the code seems less confusing to me
>
> untested, so I might overlooked something..
>
> jirka
>
>
>
> ---
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 4e7d72dfbcd4..7479664844ea 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1309,6 +1309,7 @@ enum bpf_tramp_prog_type {
> BPF_TRAMP_MODIFY_RETURN,
> BPF_TRAMP_MAX,
> BPF_TRAMP_REPLACE, /* more than MAX */
> + BPF_TRAMP_FSESSION,
> };
>
> struct bpf_tramp_image {
> @@ -1861,6 +1862,7 @@ struct bpf_link_ops {
> struct bpf_tramp_link {
> struct bpf_link link;
> struct hlist_node tramp_hlist;
> + struct hlist_node extra_hlist;
> u64 cookie;
> };
In this way, it indeed can make the update of the hlist more clear. However,
I think that you missed the reading of the hlist as I mentioned above.
You can't add both the "tramp_hlist" and "extra_hlist" to the same hlist. If
so, how do we iterate the hlist? Do I miss something?
Thanks!
Menglong Dong
>
[......]
> void test_tracing_failure(void)
>
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH bpf-next v5 01/10] bpf: add fsession support
2026-01-02 9:21 ` Menglong Dong
@ 2026-01-02 12:11 ` Jiri Olsa
0 siblings, 0 replies; 14+ messages in thread
From: Jiri Olsa @ 2026-01-02 12:11 UTC (permalink / raw)
To: Menglong Dong
Cc: Menglong Dong, Jiri Olsa, ast, andrii, daniel, martin.lau,
eddyz87, song, yonghong.song, john.fastabend, kpsingh, sdf,
haoluo, davem, dsahern, tglx, mingo, jiang.biao, bp, dave.hansen,
x86, hpa, bpf, netdev, linux-kernel
On Fri, Jan 02, 2026 at 05:21:42PM +0800, Menglong Dong wrote:
SNIP
> > ---
> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> > index 4e7d72dfbcd4..7479664844ea 100644
> > --- a/include/linux/bpf.h
> > +++ b/include/linux/bpf.h
> > @@ -1309,6 +1309,7 @@ enum bpf_tramp_prog_type {
> > BPF_TRAMP_MODIFY_RETURN,
> > BPF_TRAMP_MAX,
> > BPF_TRAMP_REPLACE, /* more than MAX */
> > + BPF_TRAMP_FSESSION,
> > };
> >
> > struct bpf_tramp_image {
> > @@ -1861,6 +1862,7 @@ struct bpf_link_ops {
> > struct bpf_tramp_link {
> > struct bpf_link link;
> > struct hlist_node tramp_hlist;
> > + struct hlist_node extra_hlist;
> > u64 cookie;
> > };
>
> In this way, it indeed can make the update of the hlist more clear. However,
> I think that you missed the reading of the hlist as I mentioned above.
> You can't add both the "tramp_hlist" and "extra_hlist" to the same hlist. If
> so, how do we iterate the hlist? Do I miss something?
ugh, it's on the same list.. nevermind then ;-)
jirka
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH bpf-next v5 02/10] bpf: use last 8-bits for the nr_args in trampoline
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 01/10] bpf: add " Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 03/10] bpf: add the kfunc bpf_fsession_is_return Menglong Dong
` (7 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
For now, ctx[-1] is used to store the nr_args in the trampoline. However,
1-byte is enough to store such information. Therefore, we use only the
last byte of ctx[-1] to store the nr_args, and reserve the rest for other
usages.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
kernel/bpf/verifier.c | 35 +++++++++++++++++++----------------
kernel/trace/bpf_trace.c | 4 ++--
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index b9714a7c3c5f..a99e286a504d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -23275,15 +23275,16 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
insn->imm == BPF_FUNC_get_func_arg) {
/* Load nr_args from ctx - 8 */
insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
- insn_buf[1] = BPF_JMP32_REG(BPF_JGE, BPF_REG_2, BPF_REG_0, 6);
- insn_buf[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 3);
- insn_buf[3] = BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1);
- insn_buf[4] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0);
- insn_buf[5] = BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0);
- insn_buf[6] = BPF_MOV64_IMM(BPF_REG_0, 0);
- insn_buf[7] = BPF_JMP_A(1);
- insn_buf[8] = BPF_MOV64_IMM(BPF_REG_0, -EINVAL);
- cnt = 9;
+ insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF);
+ insn_buf[2] = BPF_JMP32_REG(BPF_JGE, BPF_REG_2, BPF_REG_0, 6);
+ insn_buf[3] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 3);
+ insn_buf[4] = BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1);
+ insn_buf[5] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0);
+ insn_buf[6] = BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0);
+ insn_buf[7] = BPF_MOV64_IMM(BPF_REG_0, 0);
+ insn_buf[8] = BPF_JMP_A(1);
+ insn_buf[9] = BPF_MOV64_IMM(BPF_REG_0, -EINVAL);
+ cnt = 10;
new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
if (!new_prog)
@@ -23303,12 +23304,13 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
eatype == BPF_MODIFY_RETURN) {
/* Load nr_args from ctx - 8 */
insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
- insn_buf[1] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, 3);
- insn_buf[2] = BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1);
- insn_buf[3] = BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0);
- insn_buf[4] = BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0);
- insn_buf[5] = BPF_MOV64_IMM(BPF_REG_0, 0);
- cnt = 6;
+ insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF);
+ insn_buf[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, 3);
+ insn_buf[3] = BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1);
+ insn_buf[4] = BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0);
+ insn_buf[5] = BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0);
+ insn_buf[6] = BPF_MOV64_IMM(BPF_REG_0, 0);
+ cnt = 7;
} else {
insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, -EOPNOTSUPP);
cnt = 1;
@@ -23329,8 +23331,9 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
insn->imm == BPF_FUNC_get_func_arg_cnt) {
/* Load nr_args from ctx - 8 */
insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
+ insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF);
- new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, 1);
+ new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, 2);
if (!new_prog)
return -ENOMEM;
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index d57727abaade..10c9992d2745 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -1194,7 +1194,7 @@ const struct bpf_func_proto bpf_get_branch_snapshot_proto = {
BPF_CALL_3(get_func_arg, void *, ctx, u32, n, u64 *, value)
{
/* This helper call is inlined by verifier. */
- u64 nr_args = ((u64 *)ctx)[-1];
+ u64 nr_args = ((u64 *)ctx)[-1] & 0xFF;
if ((u64) n >= nr_args)
return -EINVAL;
@@ -1214,7 +1214,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
BPF_CALL_2(get_func_ret, void *, ctx, u64 *, value)
{
/* This helper call is inlined by verifier. */
- u64 nr_args = ((u64 *)ctx)[-1];
+ u64 nr_args = ((u64 *)ctx)[-1] & 0xFF;
*value = ((u64 *)ctx)[nr_args];
return 0;
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 03/10] bpf: add the kfunc bpf_fsession_is_return
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 01/10] bpf: add " Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 02/10] bpf: use last 8-bits for the nr_args in trampoline Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 04/10] bpf: add the kfunc bpf_fsession_cookie Menglong Dong
` (6 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
If fsession exists, we will use the bit (1 << BPF_TRAMP_M_IS_RETURN) in
ctx[-1] to store the "is_return" flag.
Introduce the kfunc bpf_fsession_is_return(), which is used to tell if it
is fexit currently. Meanwhile, inline it in the verifier.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
Co-developed-by: Leon Hwang <leon.hwang@linux.dev>
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
v4:
- split out the bpf_fsession_cookie() to another patch
v3:
- merge the bpf_tracing_is_exit and bpf_fsession_cookie into a single
patch
v2:
- store the session flags after return value, instead of before nr_args
- inline the bpf_tracing_is_exit, as Jiri suggested
---
include/linux/bpf.h | 3 +++
kernel/bpf/verifier.c | 11 +++++++++-
kernel/trace/bpf_trace.c | 43 +++++++++++++++++++++++++++++++++++++---
3 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 63e1bc29485e..dc6b4109f0bf 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1213,6 +1213,9 @@ enum {
#endif
};
+#define BPF_TRAMP_M_NR_ARGS 0
+#define BPF_TRAMP_M_IS_RETURN 8
+
struct bpf_tramp_links {
struct bpf_tramp_link *links[BPF_MAX_TRAMP_LINKS];
int nr_links;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a99e286a504d..8a5787e6ab0b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12380,6 +12380,7 @@ enum special_kfunc_type {
KF___bpf_trap,
KF_bpf_task_work_schedule_signal_impl,
KF_bpf_task_work_schedule_resume_impl,
+ KF_bpf_fsession_is_return,
};
BTF_ID_LIST(special_kfunc_list)
@@ -12454,6 +12455,7 @@ BTF_ID(func, bpf_dynptr_file_discard)
BTF_ID(func, __bpf_trap)
BTF_ID(func, bpf_task_work_schedule_signal_impl)
BTF_ID(func, bpf_task_work_schedule_resume_impl)
+BTF_ID(func, bpf_fsession_is_return)
static bool is_task_work_add_kfunc(u32 func_id)
{
@@ -12508,7 +12510,8 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
struct bpf_reg_state *reg = ®s[regno];
bool arg_mem_size = false;
- if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx])
+ if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
+ meta->func_id == special_kfunc_list[KF_bpf_fsession_is_return])
return KF_ARG_PTR_TO_CTX;
/* In this function, we verify the kfunc's BTF as per the argument type,
@@ -22556,6 +22559,12 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
desc->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) {
insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1);
*cnt = 1;
+ } else if (desc->func_id == special_kfunc_list[KF_bpf_fsession_is_return]) {
+ /* Load nr_args from ctx - 8 */
+ insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
+ insn_buf[1] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, BPF_TRAMP_M_IS_RETURN);
+ insn_buf[2] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1);
+ *cnt = 3;
}
if (env->insn_aux_data[insn_idx].arg_prog) {
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 10c9992d2745..8a94a507bd51 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -3356,12 +3356,49 @@ static const struct btf_kfunc_id_set bpf_kprobe_multi_kfunc_set = {
.filter = bpf_kprobe_multi_filter,
};
-static int __init bpf_kprobe_multi_kfuncs_init(void)
+__bpf_kfunc_start_defs();
+
+__bpf_kfunc bool bpf_fsession_is_return(void *ctx)
+{
+ /* This helper call is inlined by verifier. */
+ return !!(((u64 *)ctx)[-1] & (1 << BPF_TRAMP_M_IS_RETURN));
+}
+
+__bpf_kfunc_end_defs();
+
+BTF_KFUNCS_START(tracing_kfunc_set_ids)
+BTF_ID_FLAGS(func, bpf_fsession_is_return, KF_FASTCALL)
+BTF_KFUNCS_END(tracing_kfunc_set_ids)
+
+static int bpf_tracing_filter(const struct bpf_prog *prog, u32 kfunc_id)
{
- return register_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_kprobe_multi_kfunc_set);
+ if (!btf_id_set8_contains(&tracing_kfunc_set_ids, kfunc_id))
+ return 0;
+
+ if (prog->type != BPF_PROG_TYPE_TRACING ||
+ prog->expected_attach_type != BPF_TRACE_FSESSION)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct btf_kfunc_id_set bpf_tracing_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &tracing_kfunc_set_ids,
+ .filter = bpf_tracing_filter,
+};
+
+static int __init bpf_trace_kfuncs_init(void)
+{
+ int err = 0;
+
+ err = err ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_kprobe_multi_kfunc_set);
+ err = err ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_tracing_kfunc_set);
+
+ return err;
}
-late_initcall(bpf_kprobe_multi_kfuncs_init);
+late_initcall(bpf_trace_kfuncs_init);
typedef int (*copy_fn_t)(void *dst, const void *src, u32 size, struct task_struct *tsk);
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 04/10] bpf: add the kfunc bpf_fsession_cookie
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
` (2 preceding siblings ...)
2025-12-24 13:07 ` [PATCH bpf-next v5 03/10] bpf: add the kfunc bpf_fsession_is_return Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 05/10] bpf,x86: introduce emit_st_r0_imm64() for trampoline Menglong Dong
` (5 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
Implement session cookie for fsession. In order to limit the stack usage,
we make 4 as the maximum of the cookie count.
The offset of the current cookie is stored in the
"(ctx[-1] >> BPF_TRAMP_M_COOKIE) & 0xFF". Therefore, we can get the
session cookie with ctx[-offset].
The stack will look like this:
return value -> 8 bytes
argN -> 8 bytes
...
arg1 -> 8 bytes
nr_args -> 8 bytes
ip (optional) -> 8 bytes
cookie2 -> 8 bytes
cookie1 -> 8 bytes
Inline the bpf_fsession_cookie() in the verifier too.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
v5:
- remove "cookie_cnt" in struct bpf_trampoline
v4:
- limit the maximum of the cookie count to 4
- store the session cookies before nr_regs in stack
---
include/linux/bpf.h | 15 +++++++++++++++
kernel/bpf/trampoline.c | 13 +++++++++++--
kernel/bpf/verifier.c | 20 ++++++++++++++++++--
kernel/trace/bpf_trace.c | 9 +++++++++
4 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index dc6b4109f0bf..4095f4c2f833 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1215,6 +1215,7 @@ enum {
#define BPF_TRAMP_M_NR_ARGS 0
#define BPF_TRAMP_M_IS_RETURN 8
+#define BPF_TRAMP_M_COOKIE 9
struct bpf_tramp_links {
struct bpf_tramp_link *links[BPF_MAX_TRAMP_LINKS];
@@ -1762,6 +1763,7 @@ struct bpf_prog {
enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */
call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */
call_get_func_ip:1, /* Do we call get_func_ip() */
+ call_session_cookie:1, /* Do we call bpf_fsession_cookie() */
tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */
sleepable:1; /* BPF program is sleepable */
enum bpf_prog_type type; /* Type of BPF program */
@@ -2137,6 +2139,19 @@ static inline int bpf_fsession_cnt(struct bpf_tramp_links *links)
return cnt;
}
+static inline int bpf_fsession_cookie_cnt(struct bpf_tramp_links *links)
+{
+ struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY];
+ int cnt = 0;
+
+ for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) {
+ if (fentries.links[i]->link.prog->call_session_cookie)
+ cnt++;
+ }
+
+ return cnt;
+}
+
int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
const struct bpf_ctx_arg_aux *info, u32 cnt);
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 77d474fc973a..347e92e7c54e 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -592,6 +592,8 @@ static int bpf_freplace_check_tgt_prog(struct bpf_prog *tgt_prog)
return 0;
}
+#define BPF_TRAMP_MAX_COOKIES 4
+
static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
struct bpf_trampoline *tr,
struct bpf_prog *tgt_prog)
@@ -600,7 +602,7 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
struct bpf_tramp_link *link_exiting;
struct bpf_fsession_link *fslink;
struct hlist_head *prog_list;
- int err = 0;
+ int err = 0, cookie_cnt = 0;
int cnt = 0, i;
kind = bpf_attach_type_to_tramp(link->link.prog);
@@ -637,11 +639,18 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
/* prog already linked */
return -EBUSY;
hlist_for_each_entry(link_exiting, prog_list, tramp_hlist) {
- if (link_exiting->link.prog != link->link.prog)
+ if (link_exiting->link.prog != link->link.prog) {
+ if (kind == BPF_TRAMP_FSESSION &&
+ link_exiting->link.prog->call_session_cookie)
+ cookie_cnt++;
continue;
+ }
/* prog already linked */
return -EBUSY;
}
+ if (link->link.prog->call_session_cookie &&
+ cookie_cnt >= BPF_TRAMP_MAX_COOKIES)
+ return -E2BIG;
hlist_add_head(&link->tramp_hlist, prog_list);
if (kind == BPF_TRAMP_FSESSION) {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8a5787e6ab0b..8928ce5bbeb1 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12381,6 +12381,7 @@ enum special_kfunc_type {
KF_bpf_task_work_schedule_signal_impl,
KF_bpf_task_work_schedule_resume_impl,
KF_bpf_fsession_is_return,
+ KF_bpf_fsession_cookie,
};
BTF_ID_LIST(special_kfunc_list)
@@ -12456,6 +12457,7 @@ BTF_ID(func, __bpf_trap)
BTF_ID(func, bpf_task_work_schedule_signal_impl)
BTF_ID(func, bpf_task_work_schedule_resume_impl)
BTF_ID(func, bpf_fsession_is_return)
+BTF_ID(func, bpf_fsession_cookie)
static bool is_task_work_add_kfunc(u32 func_id)
{
@@ -12511,7 +12513,8 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
bool arg_mem_size = false;
if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
- meta->func_id == special_kfunc_list[KF_bpf_fsession_is_return])
+ meta->func_id == special_kfunc_list[KF_bpf_fsession_is_return] ||
+ meta->func_id == special_kfunc_list[KF_bpf_fsession_cookie])
return KF_ARG_PTR_TO_CTX;
/* In this function, we verify the kfunc's BTF as per the argument type,
@@ -14009,7 +14012,8 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
}
- if (meta.func_id == special_kfunc_list[KF_bpf_session_cookie]) {
+ if (meta.func_id == special_kfunc_list[KF_bpf_session_cookie] ||
+ meta.func_id == special_kfunc_list[KF_bpf_fsession_cookie]) {
meta.r0_size = sizeof(u64);
meta.r0_rdonly = false;
}
@@ -14293,6 +14297,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
return err;
}
+ if (meta.func_id == special_kfunc_list[KF_bpf_fsession_cookie])
+ env->prog->call_session_cookie = true;
+
return 0;
}
@@ -22565,6 +22572,15 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
insn_buf[1] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, BPF_TRAMP_M_IS_RETURN);
insn_buf[2] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1);
*cnt = 3;
+ } else if (desc->func_id == special_kfunc_list[KF_bpf_fsession_cookie]) {
+ /* Load nr_args from ctx - 8 */
+ insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
+ insn_buf[1] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, BPF_TRAMP_M_COOKIE);
+ insn_buf[2] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF);
+ insn_buf[3] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, 3);
+ insn_buf[4] = BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1);
+ insn_buf[5] = BPF_ALU64_IMM(BPF_NEG, BPF_REG_0, 0);
+ *cnt = 6;
}
if (env->insn_aux_data[insn_idx].arg_prog) {
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 8a94a507bd51..67f673c41d50 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -3364,10 +3364,19 @@ __bpf_kfunc bool bpf_fsession_is_return(void *ctx)
return !!(((u64 *)ctx)[-1] & (1 << BPF_TRAMP_M_IS_RETURN));
}
+__bpf_kfunc u64 *bpf_fsession_cookie(void *ctx)
+{
+ /* This helper call is inlined by verifier. */
+ u64 off = (((u64 *)ctx)[-1] >> BPF_TRAMP_M_COOKIE) & 0xFF;
+
+ return &((u64 *)ctx)[-off];
+}
+
__bpf_kfunc_end_defs();
BTF_KFUNCS_START(tracing_kfunc_set_ids)
BTF_ID_FLAGS(func, bpf_fsession_is_return, KF_FASTCALL)
+BTF_ID_FLAGS(func, bpf_fsession_cookie, KF_FASTCALL)
BTF_KFUNCS_END(tracing_kfunc_set_ids)
static int bpf_tracing_filter(const struct bpf_prog *prog, u32 kfunc_id)
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 05/10] bpf,x86: introduce emit_st_r0_imm64() for trampoline
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
` (3 preceding siblings ...)
2025-12-24 13:07 ` [PATCH bpf-next v5 04/10] bpf: add the kfunc bpf_fsession_cookie Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 06/10] bpf,x86: add fsession support for x86_64 Menglong Dong
` (4 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
Introduce the helper emit_st_r0_imm64(), which is used to store a imm64 to
the stack with the help of r0.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
arch/x86/net/bpf_jit_comp.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index b69dc7194e2c..8cbeefb26192 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -1300,6 +1300,15 @@ static void emit_st_r12(u8 **pprog, u32 size, u32 dst_reg, int off, int imm)
emit_st_index(pprog, size, dst_reg, X86_REG_R12, off, imm);
}
+static void emit_st_r0_imm64(u8 **pprog, u64 value, int off)
+{
+ /* mov rax, value
+ * mov QWORD PTR [rbp - off], rax
+ */
+ emit_mov_imm64(pprog, BPF_REG_0, value >> 32, (u32) value);
+ emit_stx(pprog, BPF_DW, BPF_REG_FP, BPF_REG_0, -off);
+}
+
static int emit_atomic_rmw(u8 **pprog, u32 atomic_op,
u32 dst_reg, u32 src_reg, s16 off, u8 bpf_size)
{
@@ -3341,16 +3350,14 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
* mov rax, nr_regs
* mov QWORD PTR [rbp - nregs_off], rax
*/
- emit_mov_imm64(&prog, BPF_REG_0, 0, (u32) nr_regs);
- emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -nregs_off);
+ emit_st_r0_imm64(&prog, nr_regs, nregs_off);
if (flags & BPF_TRAMP_F_IP_ARG) {
/* Store IP address of the traced function:
* movabsq rax, func_addr
* mov QWORD PTR [rbp - ip_off], rax
*/
- emit_mov_imm64(&prog, BPF_REG_0, (long) func_addr >> 32, (u32) (long) func_addr);
- emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -ip_off);
+ emit_st_r0_imm64(&prog, (long)func_addr, ip_off);
}
save_args(m, &prog, regs_off, false, flags);
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 06/10] bpf,x86: add fsession support for x86_64
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
` (4 preceding siblings ...)
2025-12-24 13:07 ` [PATCH bpf-next v5 05/10] bpf,x86: introduce emit_st_r0_imm64() for trampoline Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 07/10] libbpf: add fsession support Menglong Dong
` (3 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
Add BPF_TRACE_FSESSION supporting to x86_64, including:
1. clear the return value in the stack before fentry to make the fentry
of the fsession can only get 0 with bpf_get_func_ret().
2. clear all the session cookies' value in the stack.
2. store the index of the cookie to ctx[-1] before the calling to fsession
3. store the "is_return" flag to ctx[-1] before the calling to fexit of
the fsession.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
Co-developed-by: Leon Hwang <leon.hwang@linux.dev>
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
v5:
- add the variable "func_meta"
- define cookie_off in a new line
v4:
- some adjustment to the 1st patch, such as we get the fsession prog from
fentry and fexit hlist
- remove the supporting of skipping fexit with fentry return non-zero
v2:
- add session cookie support
- add the session stuff after return value, instead of before nr_args
---
arch/x86/net/bpf_jit_comp.c | 33 ++++++++++++++++++++++++++++++---
1 file changed, 30 insertions(+), 3 deletions(-)
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 8cbeefb26192..164c745d913c 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -3086,12 +3086,17 @@ static int emit_cond_near_jump(u8 **pprog, void *func, void *ip, u8 jmp_cond)
static int invoke_bpf(const struct btf_func_model *m, u8 **pprog,
struct bpf_tramp_links *tl, int stack_size,
int run_ctx_off, bool save_ret,
- void *image, void *rw_image)
+ void *image, void *rw_image, u64 func_meta)
{
int i;
u8 *prog = *pprog;
for (i = 0; i < tl->nr_links; i++) {
+ if (tl->links[i]->link.prog->call_session_cookie) {
+ /* 'stack_size + 8' is the offset of func_md in stack */
+ emit_st_r0_imm64(&prog, func_meta, stack_size + 8);
+ func_meta -= (1 << BPF_TRAMP_M_COOKIE);
+ }
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size,
run_ctx_off, save_ret, image, rw_image))
return -EINVAL;
@@ -3214,7 +3219,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
void *orig_call = func_addr;
+ int cookie_off, cookie_cnt;
u8 **branches = NULL;
+ u64 func_meta;
u8 *prog;
bool save_ret;
@@ -3282,6 +3289,11 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
ip_off = stack_size;
+ cookie_cnt = bpf_fsession_cookie_cnt(tlinks);
+ /* room for session cookies */
+ stack_size += cookie_cnt * 8;
+ cookie_off = stack_size;
+
stack_size += 8;
rbx_off = stack_size;
@@ -3372,9 +3384,19 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
}
}
+ if (bpf_fsession_cnt(tlinks)) {
+ /* clear all the session cookies' value */
+ for (int i = 0; i < cookie_cnt; i++)
+ emit_st_r0_imm64(&prog, 0, cookie_off - 8 * i);
+ /* clear the return value to make sure fentry always get 0 */
+ emit_st_r0_imm64(&prog, 0, 8);
+ }
+ func_meta = nr_regs + (((cookie_off - regs_off) / 8) << BPF_TRAMP_M_COOKIE);
+
if (fentry->nr_links) {
if (invoke_bpf(m, &prog, fentry, regs_off, run_ctx_off,
- flags & BPF_TRAMP_F_RET_FENTRY_RET, image, rw_image))
+ flags & BPF_TRAMP_F_RET_FENTRY_RET, image, rw_image,
+ func_meta))
return -EINVAL;
}
@@ -3434,9 +3456,14 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
}
}
+ /* set the "is_return" flag for fsession */
+ func_meta += (1 << BPF_TRAMP_M_IS_RETURN);
+ if (bpf_fsession_cnt(tlinks))
+ emit_st_r0_imm64(&prog, func_meta, nregs_off);
+
if (fexit->nr_links) {
if (invoke_bpf(m, &prog, fexit, regs_off, run_ctx_off,
- false, image, rw_image)) {
+ false, image, rw_image, func_meta)) {
ret = -EINVAL;
goto cleanup;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 07/10] libbpf: add fsession support
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
` (5 preceding siblings ...)
2025-12-24 13:07 ` [PATCH bpf-next v5 06/10] bpf,x86: add fsession support for x86_64 Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 08/10] selftests/bpf: add testcases for fsession Menglong Dong
` (2 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
Add BPF_TRACE_FSESSION to libbpf and bpftool.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
v5:
- remove the handling of BPF_TRACE_SESSION in legacy fallback path for
BPF_RAW_TRACEPOINT_OPEN
- use fsession terminology consistently
---
tools/bpf/bpftool/common.c | 1 +
tools/lib/bpf/bpf.c | 1 +
tools/lib/bpf/libbpf.c | 3 +++
3 files changed, 5 insertions(+)
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index e8daf963ecef..8bfcff9e2f63 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -1191,6 +1191,7 @@ const char *bpf_attach_type_input_str(enum bpf_attach_type t)
case BPF_TRACE_FENTRY: return "fentry";
case BPF_TRACE_FEXIT: return "fexit";
case BPF_MODIFY_RETURN: return "mod_ret";
+ case BPF_TRACE_FSESSION: return "fsession";
case BPF_SK_REUSEPORT_SELECT: return "sk_skb_reuseport_select";
case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE: return "sk_skb_reuseport_select_or_migrate";
default: return libbpf_bpf_attach_type_str(t);
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 21b57a629916..5846de364209 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -794,6 +794,7 @@ int bpf_link_create(int prog_fd, int target_fd,
case BPF_TRACE_FENTRY:
case BPF_TRACE_FEXIT:
case BPF_MODIFY_RETURN:
+ case BPF_TRACE_FSESSION:
case BPF_LSM_MAC:
attr.link_create.tracing.cookie = OPTS_GET(opts, tracing.cookie, 0);
if (!OPTS_ZEROED(opts, tracing))
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index c7c79014d46c..10f96e8f8ce1 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -115,6 +115,7 @@ static const char * const attach_type_name[] = {
[BPF_TRACE_FENTRY] = "trace_fentry",
[BPF_TRACE_FEXIT] = "trace_fexit",
[BPF_MODIFY_RETURN] = "modify_return",
+ [BPF_TRACE_FSESSION] = "trace_fsession",
[BPF_LSM_MAC] = "lsm_mac",
[BPF_LSM_CGROUP] = "lsm_cgroup",
[BPF_SK_LOOKUP] = "sk_lookup",
@@ -9853,6 +9854,8 @@ static const struct bpf_sec_def section_defs[] = {
SEC_DEF("fentry.s+", TRACING, BPF_TRACE_FENTRY, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace),
SEC_DEF("fmod_ret.s+", TRACING, BPF_MODIFY_RETURN, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace),
SEC_DEF("fexit.s+", TRACING, BPF_TRACE_FEXIT, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace),
+ SEC_DEF("fsession+", TRACING, BPF_TRACE_FSESSION, SEC_ATTACH_BTF, attach_trace),
+ SEC_DEF("fsession.s+", TRACING, BPF_TRACE_FSESSION, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace),
SEC_DEF("freplace+", EXT, 0, SEC_ATTACH_BTF, attach_trace),
SEC_DEF("lsm+", LSM, BPF_LSM_MAC, SEC_ATTACH_BTF, attach_lsm),
SEC_DEF("lsm.s+", LSM, BPF_LSM_MAC, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_lsm),
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 08/10] selftests/bpf: add testcases for fsession
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
` (6 preceding siblings ...)
2025-12-24 13:07 ` [PATCH bpf-next v5 07/10] libbpf: add fsession support Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 09/10] selftests/bpf: add testcases for fsession cookie Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 10/10] selftests/bpf: test fsession mixed with fentry and fexit Menglong Dong
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
Add testcases for BPF_TRACE_FSESSION. The function arguments and return
value are tested both in the entry and exit. And the kfunc
bpf_fsession_is_ret() is also tested.
As the layout of the stack changed for fsession, so we also test
bpf_get_func_ip() for it.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
v3:
- restructure the testcase by combine the testcases for session cookie and
get_func_ip into one patch
---
.../selftests/bpf/prog_tests/fsession_test.c | 90 ++++++++++++++
.../selftests/bpf/progs/fsession_test.c | 110 ++++++++++++++++++
2 files changed, 200 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/fsession_test.c
create mode 100644 tools/testing/selftests/bpf/progs/fsession_test.c
diff --git a/tools/testing/selftests/bpf/prog_tests/fsession_test.c b/tools/testing/selftests/bpf/prog_tests/fsession_test.c
new file mode 100644
index 000000000000..83f3953a1ff6
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/fsession_test.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 ChinaTelecom */
+#include <test_progs.h>
+#include "fsession_test.skel.h"
+
+static int check_result(struct fsession_test *skel)
+{
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+ int err, prog_fd;
+
+ /* Trigger test function calls */
+ prog_fd = bpf_program__fd(skel->progs.test1);
+ err = bpf_prog_test_run_opts(prog_fd, &topts);
+ if (!ASSERT_OK(err, "test_run_opts err"))
+ return err;
+ if (!ASSERT_OK(topts.retval, "test_run_opts retval"))
+ return topts.retval;
+
+ for (int i = 0; i < sizeof(*skel->bss) / sizeof(__u64); i++) {
+ if (!ASSERT_EQ(((__u64 *)skel->bss)[i], 1, "test_result"))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void test_fsession_basic(void)
+{
+ struct fsession_test *skel = NULL;
+ int err;
+
+ skel = fsession_test__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "fsession_test__open_and_load"))
+ goto cleanup;
+
+ err = fsession_test__attach(skel);
+ if (!ASSERT_OK(err, "fsession_attach"))
+ goto cleanup;
+
+ check_result(skel);
+cleanup:
+ fsession_test__destroy(skel);
+}
+
+static void test_fsession_reattach(void)
+{
+ struct fsession_test *skel = NULL;
+ int err;
+
+ skel = fsession_test__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "fsession_test__open_and_load"))
+ goto cleanup;
+
+ /* First attach */
+ err = fsession_test__attach(skel);
+ if (!ASSERT_OK(err, "fsession_first_attach"))
+ goto cleanup;
+
+ if (check_result(skel))
+ goto cleanup;
+
+ /* Detach */
+ fsession_test__detach(skel);
+
+ /* Reset counters */
+ memset(skel->bss, 0, sizeof(*skel->bss));
+
+ /* Second attach */
+ err = fsession_test__attach(skel);
+ if (!ASSERT_OK(err, "fsession_second_attach"))
+ goto cleanup;
+
+ if (check_result(skel))
+ goto cleanup;
+
+cleanup:
+ fsession_test__destroy(skel);
+}
+
+void test_fsession_test(void)
+{
+#if !defined(__x86_64__)
+ test__skip();
+ return;
+#endif
+ if (test__start_subtest("fsession_basic"))
+ test_fsession_basic();
+ if (test__start_subtest("fsession_reattach"))
+ test_fsession_reattach();
+}
diff --git a/tools/testing/selftests/bpf/progs/fsession_test.c b/tools/testing/selftests/bpf/progs/fsession_test.c
new file mode 100644
index 000000000000..b180e339c17f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/fsession_test.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 ChinaTelecom */
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+__u64 test1_entry_result = 0;
+__u64 test1_exit_result = 0;
+
+SEC("fsession/bpf_fentry_test1")
+int BPF_PROG(test1, int a, int ret)
+{
+ bool is_exit = bpf_fsession_is_return(ctx);
+
+ if (!is_exit) {
+ test1_entry_result = a == 1 && ret == 0;
+ return 0;
+ }
+
+ test1_exit_result = a == 1 && ret == 2;
+ return 0;
+}
+
+__u64 test2_entry_result = 0;
+__u64 test2_exit_result = 0;
+
+SEC("fsession/bpf_fentry_test3")
+int BPF_PROG(test2, char a, int b, __u64 c, int ret)
+{
+ bool is_exit = bpf_fsession_is_return(ctx);
+
+ if (!is_exit) {
+ test2_entry_result = a == 4 && b == 5 && c == 6 && ret == 0;
+ return 0;
+ }
+
+ test2_exit_result = a == 4 && b == 5 && c == 6 && ret == 15;
+ return 0;
+}
+
+__u64 test3_entry_result = 0;
+__u64 test3_exit_result = 0;
+
+SEC("fsession/bpf_fentry_test4")
+int BPF_PROG(test3, void *a, char b, int c, __u64 d, int ret)
+{
+ bool is_exit = bpf_fsession_is_return(ctx);
+
+ if (!is_exit) {
+ test3_entry_result = a == (void *)7 && b == 8 && c == 9 && d == 10 && ret == 0;
+ return 0;
+ }
+
+ test3_exit_result = a == (void *)7 && b == 8 && c == 9 && d == 10 && ret == 34;
+ return 0;
+}
+
+__u64 test4_entry_result = 0;
+__u64 test4_exit_result = 0;
+
+SEC("fsession/bpf_fentry_test5")
+int BPF_PROG(test4, __u64 a, void *b, short c, int d, __u64 e, int ret)
+{
+ bool is_exit = bpf_fsession_is_return(ctx);
+
+ if (!is_exit) {
+ test4_entry_result = a == 11 && b == (void *)12 && c == 13 && d == 14 &&
+ e == 15 && ret == 0;
+ return 0;
+ }
+
+ test4_exit_result = a == 11 && b == (void *)12 && c == 13 && d == 14 &&
+ e == 15 && ret == 65;
+ return 0;
+}
+
+__u64 test5_entry_result = 0;
+__u64 test5_exit_result = 0;
+
+SEC("fsession/bpf_fentry_test7")
+int BPF_PROG(test5, struct bpf_fentry_test_t *arg, int ret)
+{
+ bool is_exit = bpf_fsession_is_return(ctx);
+
+ if (!is_exit) {
+ if (!arg)
+ test5_entry_result = ret == 0;
+ return 0;
+ }
+
+ if (!arg)
+ test5_exit_result = 1;
+ return 0;
+}
+
+__u64 test6_entry_result = 0;
+__u64 test6_exit_result = 0;
+SEC("fsession/bpf_fentry_test1")
+int BPF_PROG(test6, int a)
+{
+ __u64 addr = bpf_get_func_ip(ctx);
+
+ if (bpf_fsession_is_return(ctx))
+ test6_exit_result = (const void *) addr == &bpf_fentry_test1;
+ else
+ test6_entry_result = (const void *) addr == &bpf_fentry_test1;
+ return 0;
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 09/10] selftests/bpf: add testcases for fsession cookie
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
` (7 preceding siblings ...)
2025-12-24 13:07 ` [PATCH bpf-next v5 08/10] selftests/bpf: add testcases for fsession Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
2025-12-24 13:07 ` [PATCH bpf-next v5 10/10] selftests/bpf: test fsession mixed with fentry and fexit Menglong Dong
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
Test session cookie for fsession. Multiple fsession BPF progs is attached
to bpf_fentry_test1() and session cookie is read and write in the
testcase.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
v3:
- restructure the testcase by combine the testcases for session cookie and
get_func_ip into one patch
---
.../selftests/bpf/prog_tests/fsession_test.c | 25 +++++++
.../selftests/bpf/progs/fsession_test.c | 72 +++++++++++++++++++
2 files changed, 97 insertions(+)
diff --git a/tools/testing/selftests/bpf/prog_tests/fsession_test.c b/tools/testing/selftests/bpf/prog_tests/fsession_test.c
index 83f3953a1ff6..2459f9db1c92 100644
--- a/tools/testing/selftests/bpf/prog_tests/fsession_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/fsession_test.c
@@ -77,6 +77,29 @@ static void test_fsession_reattach(void)
fsession_test__destroy(skel);
}
+static void test_fsession_cookie(void)
+{
+ struct fsession_test *skel = NULL;
+ int err;
+
+ skel = fsession_test__open();
+ if (!ASSERT_OK_PTR(skel, "fsession_test__open"))
+ goto cleanup;
+
+ err = bpf_program__set_autoload(skel->progs.test11, true);
+ if (!ASSERT_OK(err, "bpf_program__set_autoload"))
+ goto cleanup;
+
+ err = fsession_test__load(skel);
+ if (!ASSERT_OK(err, "fsession_test__load"))
+ goto cleanup;
+
+ err = fsession_test__attach(skel);
+ ASSERT_EQ(err, -E2BIG, "fsession_cookie");
+cleanup:
+ fsession_test__destroy(skel);
+}
+
void test_fsession_test(void)
{
#if !defined(__x86_64__)
@@ -87,4 +110,6 @@ void test_fsession_test(void)
test_fsession_basic();
if (test__start_subtest("fsession_reattach"))
test_fsession_reattach();
+ if (test__start_subtest("fsession_cookie"))
+ test_fsession_cookie();
}
diff --git a/tools/testing/selftests/bpf/progs/fsession_test.c b/tools/testing/selftests/bpf/progs/fsession_test.c
index b180e339c17f..5630cf3bbd8b 100644
--- a/tools/testing/selftests/bpf/progs/fsession_test.c
+++ b/tools/testing/selftests/bpf/progs/fsession_test.c
@@ -108,3 +108,75 @@ int BPF_PROG(test6, int a)
test6_entry_result = (const void *) addr == &bpf_fentry_test1;
return 0;
}
+
+__u64 test7_entry_ok = 0;
+__u64 test7_exit_ok = 0;
+SEC("fsession/bpf_fentry_test1")
+int BPF_PROG(test7, int a)
+{
+ __u64 *cookie = bpf_fsession_cookie(ctx);
+
+ if (!bpf_fsession_is_return(ctx)) {
+ *cookie = 0xAAAABBBBCCCCDDDDull;
+ test7_entry_ok = *cookie == 0xAAAABBBBCCCCDDDDull;
+ return 0;
+ }
+
+ test7_exit_ok = *cookie == 0xAAAABBBBCCCCDDDDull;
+ return 0;
+}
+
+__u64 test8_entry_ok = 0;
+__u64 test8_exit_ok = 0;
+
+SEC("fsession/bpf_fentry_test1")
+int BPF_PROG(test8, int a)
+{
+ __u64 *cookie = bpf_fsession_cookie(ctx);
+
+ if (!bpf_fsession_is_return(ctx)) {
+ *cookie = 0x1111222233334444ull;
+ test8_entry_ok = *cookie == 0x1111222233334444ull;
+ return 0;
+ }
+
+ test8_exit_ok = *cookie == 0x1111222233334444ull;
+ return 0;
+}
+
+__u64 test9_entry_result = 0;
+__u64 test9_exit_result = 0;
+
+SEC("fsession/bpf_fentry_test1")
+int BPF_PROG(test9, int a, int ret)
+{
+ __u64 *cookie = bpf_fsession_cookie(ctx);
+
+ if (!bpf_fsession_is_return(ctx)) {
+ test9_entry_result = a == 1 && ret == 0;
+ *cookie = 0x123456ULL;
+ return 0;
+ }
+
+ test9_exit_result = a == 1 && ret == 2 && *cookie == 0x123456ULL;
+ return 0;
+}
+
+SEC("fsession/bpf_fentry_test1")
+int BPF_PROG(test10, int a, int ret)
+{
+ __u64 *cookie = bpf_fsession_cookie(ctx);
+
+ *cookie = 0;
+ return 0;
+}
+
+/* This is the 5th cookie, so it should fail */
+SEC("?fsession/bpf_fentry_test1")
+int BPF_PROG(test11, int a, int ret)
+{
+ __u64 *cookie = bpf_fsession_cookie(ctx);
+
+ *cookie = 0;
+ return 0;
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH bpf-next v5 10/10] selftests/bpf: test fsession mixed with fentry and fexit
2025-12-24 13:07 [PATCH bpf-next v5 00/10] bpf: fsession support Menglong Dong
` (8 preceding siblings ...)
2025-12-24 13:07 ` [PATCH bpf-next v5 09/10] selftests/bpf: add testcases for fsession cookie Menglong Dong
@ 2025-12-24 13:07 ` Menglong Dong
9 siblings, 0 replies; 14+ messages in thread
From: Menglong Dong @ 2025-12-24 13:07 UTC (permalink / raw)
To: ast, andrii
Cc: daniel, martin.lau, eddyz87, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, davem, dsahern, tglx, mingo,
jiang.biao, bp, dave.hansen, x86, hpa, bpf, netdev, linux-kernel
Test the fsession when it is used together with fentry, fexit.
Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
.../testing/selftests/bpf/progs/fsession_test.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/fsession_test.c b/tools/testing/selftests/bpf/progs/fsession_test.c
index 5630cf3bbd8b..acf76e20284b 100644
--- a/tools/testing/selftests/bpf/progs/fsession_test.c
+++ b/tools/testing/selftests/bpf/progs/fsession_test.c
@@ -180,3 +180,19 @@ int BPF_PROG(test11, int a, int ret)
*cookie = 0;
return 0;
}
+
+__u64 test12_result = 0;
+SEC("fexit/bpf_fentry_test1")
+int BPF_PROG(test12, int a, int ret)
+{
+ test12_result = a == 1 && ret == 2;
+ return 0;
+}
+
+__u64 test13_result = 0;
+SEC("fentry/bpf_fentry_test1")
+int BPF_PROG(test13, int a)
+{
+ test13_result = a == 1;
+ return 0;
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread