* [PATCH bpf-next v2 0/2] bpf: Introduce bpf_in_interrupt kfunc
@ 2025-08-25 13:14 Leon Hwang
2025-08-25 13:15 ` [PATCH bpf-next v2 1/2] " Leon Hwang
2025-08-25 13:15 ` [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test " Leon Hwang
0 siblings, 2 replies; 12+ messages in thread
From: Leon Hwang @ 2025-08-25 13:14 UTC (permalink / raw)
To: bpf
Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
leon.hwang, kernel-patches-bot
Filtering pid_tgid is meaningless when the current task is preempted by
an interrupt.
To address this, introduce the bpf_in_interrupt kfunc, which allows BPF
programs to determine whether they are executing in interrupt context.
Internally, bpf_in_interrupt() is a thin wrapper around in_interrupt().
It is marked as fastcall function.
On x86_64, it is inlined for efficiency.
Changes:
v1 -> v2:
* Fix a build error reported by test bot.
Leon Hwang (2):
bpf: Introduce bpf_in_interrupt kfunc
selftests/bpf: Add case to test bpf_in_interrupt kfunc
kernel/bpf/helpers.c | 9 +++++++++
kernel/bpf/verifier.c | 11 +++++++++++
tools/testing/selftests/bpf/progs/irq.c | 7 +++++++
3 files changed, 27 insertions(+)
--
2.50.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH bpf-next v2 1/2] bpf: Introduce bpf_in_interrupt kfunc
2025-08-25 13:14 [PATCH bpf-next v2 0/2] bpf: Introduce bpf_in_interrupt kfunc Leon Hwang
@ 2025-08-25 13:15 ` Leon Hwang
2025-08-25 15:17 ` Alexei Starovoitov
2025-08-25 13:15 ` [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test " Leon Hwang
1 sibling, 1 reply; 12+ messages in thread
From: Leon Hwang @ 2025-08-25 13:15 UTC (permalink / raw)
To: bpf
Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
leon.hwang, kernel-patches-bot
Filtering pid_tgid is meaningless when the current task is preempted by
an interrupt.
To address this, introduce the bpf_in_interrupt kfunc, which allows BPF
programs to determine whether they are executing in interrupt context.
This enables programs to avoid applying pid_tgid filtering when running
in such contexts.
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
kernel/bpf/helpers.c | 9 +++++++++
kernel/bpf/verifier.c | 11 +++++++++++
2 files changed, 20 insertions(+)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 401b4932cc49f..38991b7b4a9e9 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -3711,6 +3711,14 @@ __bpf_kfunc int bpf_strstr(const char *s1__ign, const char *s2__ign)
return bpf_strnstr(s1__ign, s2__ign, XATTR_SIZE_MAX);
}
+/**
+ * bpf_in_interrupt - Check whether it's in interrupt context
+ */
+__bpf_kfunc int bpf_in_interrupt(void)
+{
+ return in_interrupt();
+}
+
__bpf_kfunc_end_defs();
BTF_KFUNCS_START(generic_btf_ids)
@@ -3751,6 +3759,7 @@ BTF_ID_FLAGS(func, bpf_throw)
#ifdef CONFIG_BPF_EVENTS
BTF_ID_FLAGS(func, bpf_send_signal_task, KF_TRUSTED_ARGS)
#endif
+BTF_ID_FLAGS(func, bpf_in_interrupt, KF_FASTCALL)
BTF_KFUNCS_END(generic_btf_ids)
static const struct btf_kfunc_id_set generic_kfunc_set = {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5c9dd16b2c56b..e30ecbfc29dad 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12259,6 +12259,7 @@ enum special_kfunc_type {
KF_bpf_res_spin_lock_irqsave,
KF_bpf_res_spin_unlock_irqrestore,
KF___bpf_trap,
+ KF_bpf_in_interrupt,
};
BTF_ID_LIST(special_kfunc_list)
@@ -12327,6 +12328,7 @@ BTF_ID(func, bpf_res_spin_unlock)
BTF_ID(func, bpf_res_spin_lock_irqsave)
BTF_ID(func, bpf_res_spin_unlock_irqrestore)
BTF_ID(func, __bpf_trap)
+BTF_ID(func, bpf_in_interrupt)
static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta)
{
@@ -21977,6 +21979,15 @@ 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_in_interrupt]) {
+#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
+ insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
+ insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
+ insn_buf[2] = BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0);
+ insn_buf[3] = BPF_ALU32_IMM(BPF_AND, BPF_REG_0, NMI_MASK | HARDIRQ_MASK |
+ (IS_ENABLED(CONFIG_PREEMPT_RT) ? 0 : SOFTIRQ_MASK));
+ *cnt = 4;
+#endif
}
if (env->insn_aux_data[insn_idx].arg_prog) {
--
2.50.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test bpf_in_interrupt kfunc
2025-08-25 13:14 [PATCH bpf-next v2 0/2] bpf: Introduce bpf_in_interrupt kfunc Leon Hwang
2025-08-25 13:15 ` [PATCH bpf-next v2 1/2] " Leon Hwang
@ 2025-08-25 13:15 ` Leon Hwang
2025-08-25 17:26 ` Eduard Zingerman
1 sibling, 1 reply; 12+ messages in thread
From: Leon Hwang @ 2025-08-25 13:15 UTC (permalink / raw)
To: bpf
Cc: ast, andrii, daniel, martin.lau, eddyz87, song, yonghong.song,
leon.hwang, kernel-patches-bot
cd tools/testing/selftests/bpf
./test_progs -t irq
#143/29 irq/in_interrupt:OK
#143 irq:OK
Summary: 1/34 PASSED, 0 SKIPPED, 0 FAILED
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
tools/testing/selftests/bpf/progs/irq.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
index 74d912b22de90..65a796fd1d615 100644
--- a/tools/testing/selftests/bpf/progs/irq.c
+++ b/tools/testing/selftests/bpf/progs/irq.c
@@ -563,4 +563,11 @@ int irq_wrong_kfunc_class_2(struct __sk_buff *ctx)
return 0;
}
+SEC("?tc")
+__success
+int in_interrupt(struct __sk_buff *ctx)
+{
+ return bpf_in_interrupt();
+}
+
char _license[] SEC("license") = "GPL";
--
2.50.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpf: Introduce bpf_in_interrupt kfunc
2025-08-25 13:15 ` [PATCH bpf-next v2 1/2] " Leon Hwang
@ 2025-08-25 15:17 ` Alexei Starovoitov
2025-08-26 3:00 ` Leon Hwang
0 siblings, 1 reply; 12+ messages in thread
From: Alexei Starovoitov @ 2025-08-25 15:17 UTC (permalink / raw)
To: Leon Hwang
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard, Song Liu, Yonghong Song,
kernel-patches-bot
On Mon, Aug 25, 2025 at 6:15 AM Leon Hwang <leon.hwang@linux.dev> wrote:
>
> Filtering pid_tgid is meaningless when the current task is preempted by
> an interrupt.
>
> To address this, introduce the bpf_in_interrupt kfunc, which allows BPF
> programs to determine whether they are executing in interrupt context.
>
> This enables programs to avoid applying pid_tgid filtering when running
> in such contexts.
>
> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> ---
> kernel/bpf/helpers.c | 9 +++++++++
> kernel/bpf/verifier.c | 11 +++++++++++
> 2 files changed, 20 insertions(+)
>
> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> index 401b4932cc49f..38991b7b4a9e9 100644
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c
> @@ -3711,6 +3711,14 @@ __bpf_kfunc int bpf_strstr(const char *s1__ign, const char *s2__ign)
> return bpf_strnstr(s1__ign, s2__ign, XATTR_SIZE_MAX);
> }
>
> +/**
> + * bpf_in_interrupt - Check whether it's in interrupt context
> + */
> +__bpf_kfunc int bpf_in_interrupt(void)
> +{
> + return in_interrupt();
> +}
It doesn't scale. Next thing people will ask for hard vs soft irq.
> +
> __bpf_kfunc_end_defs();
>
> BTF_KFUNCS_START(generic_btf_ids)
> @@ -3751,6 +3759,7 @@ BTF_ID_FLAGS(func, bpf_throw)
> #ifdef CONFIG_BPF_EVENTS
> BTF_ID_FLAGS(func, bpf_send_signal_task, KF_TRUSTED_ARGS)
> #endif
> +BTF_ID_FLAGS(func, bpf_in_interrupt, KF_FASTCALL)
> BTF_KFUNCS_END(generic_btf_ids)
>
> static const struct btf_kfunc_id_set generic_kfunc_set = {
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5c9dd16b2c56b..e30ecbfc29dad 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -12259,6 +12259,7 @@ enum special_kfunc_type {
> KF_bpf_res_spin_lock_irqsave,
> KF_bpf_res_spin_unlock_irqrestore,
> KF___bpf_trap,
> + KF_bpf_in_interrupt,
> };
>
> BTF_ID_LIST(special_kfunc_list)
> @@ -12327,6 +12328,7 @@ BTF_ID(func, bpf_res_spin_unlock)
> BTF_ID(func, bpf_res_spin_lock_irqsave)
> BTF_ID(func, bpf_res_spin_unlock_irqrestore)
> BTF_ID(func, __bpf_trap)
> +BTF_ID(func, bpf_in_interrupt)
>
> static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta)
> {
> @@ -21977,6 +21979,15 @@ 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_in_interrupt]) {
> +#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
> + insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
I think bpf_per_cpu_ptr() should already be able to read that per cpu var.
> + insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
> + insn_buf[2] = BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0);
> + insn_buf[3] = BPF_ALU32_IMM(BPF_AND, BPF_REG_0, NMI_MASK | HARDIRQ_MASK |
> + (IS_ENABLED(CONFIG_PREEMPT_RT) ? 0 : SOFTIRQ_MASK));
This is still wrong in PREEMPT_RT.
pw-bot: cr
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test bpf_in_interrupt kfunc
2025-08-25 13:15 ` [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test " Leon Hwang
@ 2025-08-25 17:26 ` Eduard Zingerman
2025-08-26 3:05 ` Leon Hwang
0 siblings, 1 reply; 12+ messages in thread
From: Eduard Zingerman @ 2025-08-25 17:26 UTC (permalink / raw)
To: Leon Hwang, bpf
Cc: ast, andrii, daniel, martin.lau, song, yonghong.song,
kernel-patches-bot
On Mon, 2025-08-25 at 21:15 +0800, Leon Hwang wrote:
> cd tools/testing/selftests/bpf
> ./test_progs -t irq
> #143/29 irq/in_interrupt:OK
> #143 irq:OK
> Summary: 1/34 PASSED, 0 SKIPPED, 0 FAILED
>
> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> ---
> tools/testing/selftests/bpf/progs/irq.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
> index 74d912b22de90..65a796fd1d615 100644
> --- a/tools/testing/selftests/bpf/progs/irq.c
> +++ b/tools/testing/selftests/bpf/progs/irq.c
> @@ -563,4 +563,11 @@ int irq_wrong_kfunc_class_2(struct __sk_buff *ctx)
> return 0;
> }
>
> +SEC("?tc")
> +__success
Could you please extend this test to verify generated x86 assembly
code? (see __arch_x86_64 and __jited macro usage in verifier_tailcall_jit.c).
Also, is it necessary to extend this test to actually verify returned
value?
> +int in_interrupt(struct __sk_buff *ctx)
> +{
> + return bpf_in_interrupt();
> +}
> +
> char _license[] SEC("license") = "GPL";
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpf: Introduce bpf_in_interrupt kfunc
2025-08-25 15:17 ` Alexei Starovoitov
@ 2025-08-26 3:00 ` Leon Hwang
2025-08-26 22:18 ` Alexei Starovoitov
0 siblings, 1 reply; 12+ messages in thread
From: Leon Hwang @ 2025-08-26 3:00 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard, Song Liu, Yonghong Song,
kernel-patches-bot
On 25/8/25 23:17, Alexei Starovoitov wrote:
> On Mon, Aug 25, 2025 at 6:15 AM Leon Hwang <leon.hwang@linux.dev> wrote:
>>
>> Filtering pid_tgid is meaningless when the current task is preempted by
>> an interrupt.
>>
>> To address this, introduce the bpf_in_interrupt kfunc, which allows BPF
>> programs to determine whether they are executing in interrupt context.
>>
>> This enables programs to avoid applying pid_tgid filtering when running
>> in such contexts.
>>
>> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
>> ---
>> kernel/bpf/helpers.c | 9 +++++++++
>> kernel/bpf/verifier.c | 11 +++++++++++
>> 2 files changed, 20 insertions(+)
>>
>> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
>> index 401b4932cc49f..38991b7b4a9e9 100644
>> --- a/kernel/bpf/helpers.c
>> +++ b/kernel/bpf/helpers.c
>> @@ -3711,6 +3711,14 @@ __bpf_kfunc int bpf_strstr(const char *s1__ign, const char *s2__ign)
>> return bpf_strnstr(s1__ign, s2__ign, XATTR_SIZE_MAX);
>> }
>>
>> +/**
>> + * bpf_in_interrupt - Check whether it's in interrupt context
>> + */
>> +__bpf_kfunc int bpf_in_interrupt(void)
>> +{
>> + return in_interrupt();
>> +}
>
> It doesn't scale. Next thing people will ask for hard vs soft irq.
>
How about adding a 'flags'?
Here are the values for 'flags':
* 0: return in_interrupt();
* 1(NMI): return in_nmi();
* 2(HARDIRQ): return in_hardirq();
* 3(SOFTIRQ): return in_softirq();
>> +
>> __bpf_kfunc_end_defs();
>>
>> BTF_KFUNCS_START(generic_btf_ids)
>> @@ -3751,6 +3759,7 @@ BTF_ID_FLAGS(func, bpf_throw)
>> #ifdef CONFIG_BPF_EVENTS
>> BTF_ID_FLAGS(func, bpf_send_signal_task, KF_TRUSTED_ARGS)
>> #endif
>> +BTF_ID_FLAGS(func, bpf_in_interrupt, KF_FASTCALL)
>> BTF_KFUNCS_END(generic_btf_ids)
>>
>> static const struct btf_kfunc_id_set generic_kfunc_set = {
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 5c9dd16b2c56b..e30ecbfc29dad 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -12259,6 +12259,7 @@ enum special_kfunc_type {
>> KF_bpf_res_spin_lock_irqsave,
>> KF_bpf_res_spin_unlock_irqrestore,
>> KF___bpf_trap,
>> + KF_bpf_in_interrupt,
>> };
>>
>> BTF_ID_LIST(special_kfunc_list)
>> @@ -12327,6 +12328,7 @@ BTF_ID(func, bpf_res_spin_unlock)
>> BTF_ID(func, bpf_res_spin_lock_irqsave)
>> BTF_ID(func, bpf_res_spin_unlock_irqrestore)
>> BTF_ID(func, __bpf_trap)
>> +BTF_ID(func, bpf_in_interrupt)
>>
>> static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta)
>> {
>> @@ -21977,6 +21979,15 @@ 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_in_interrupt]) {
>> +#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
>> + insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
>
> I think bpf_per_cpu_ptr() should already be able to read that per cpu var.
>
Correct. bpf_per_cpu_ptr() and bpf_this_cpu_ptr() are helpful to read it.
So, this patch seems useless.
>> + insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0);
>> + insn_buf[2] = BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0);
>> + insn_buf[3] = BPF_ALU32_IMM(BPF_AND, BPF_REG_0, NMI_MASK | HARDIRQ_MASK |
>> + (IS_ENABLED(CONFIG_PREEMPT_RT) ? 0 : SOFTIRQ_MASK));
>
> This is still wrong in PREEMPT_RT.
>
You are right.
Double-check the following macros:
#ifdef CONFIG_PREEMPT_RT
# define softirq_count() (current->softirq_disable_cnt &
SOFTIRQ_MASK)
# define irq_count() ((preempt_count() & (NMI_MASK |
HARDIRQ_MASK)) | softirq_count())
#else
# define softirq_count() (preempt_count() & SOFTIRQ_MASK)
# define irq_count() (preempt_count() & (NMI_MASK |
HARDIRQ_MASK | SOFTIRQ_MASK))
#endif
#define in_interrupt() (irq_count())
If PREEMPT_RT, 'softirq_count()' is missing here.
Thanks,
Leon
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test bpf_in_interrupt kfunc
2025-08-25 17:26 ` Eduard Zingerman
@ 2025-08-26 3:05 ` Leon Hwang
2025-08-26 22:31 ` Eduard Zingerman
0 siblings, 1 reply; 12+ messages in thread
From: Leon Hwang @ 2025-08-26 3:05 UTC (permalink / raw)
To: Eduard Zingerman, bpf
Cc: ast, andrii, daniel, martin.lau, song, yonghong.song,
kernel-patches-bot
On 26/8/25 01:26, Eduard Zingerman wrote:
> On Mon, 2025-08-25 at 21:15 +0800, Leon Hwang wrote:
>> cd tools/testing/selftests/bpf
>> ./test_progs -t irq
>> #143/29 irq/in_interrupt:OK
>> #143 irq:OK
>> Summary: 1/34 PASSED, 0 SKIPPED, 0 FAILED
>>
>> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
>> ---
>> tools/testing/selftests/bpf/progs/irq.c | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
>> index 74d912b22de90..65a796fd1d615 100644
>> --- a/tools/testing/selftests/bpf/progs/irq.c
>> +++ b/tools/testing/selftests/bpf/progs/irq.c
>> @@ -563,4 +563,11 @@ int irq_wrong_kfunc_class_2(struct __sk_buff *ctx)
>> return 0;
>> }
>>
>> +SEC("?tc")
>> +__success
>
> Could you please extend this test to verify generated x86 assembly
> code? (see __arch_x86_64 and __jited macro usage in verifier_tailcall_jit.c).
I’ll try to extend it, depending on the specific x86 implementation.
> Also, is it necessary to extend this test to actually verify returned
> value?
Not necessary — let’s just return 0 here.
Thanks,
Leon
>
>> +int in_interrupt(struct __sk_buff *ctx)
>> +{
>> + return bpf_in_interrupt();
>> +}
>> +
>> char _license[] SEC("license") = "GPL";
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpf: Introduce bpf_in_interrupt kfunc
2025-08-26 3:00 ` Leon Hwang
@ 2025-08-26 22:18 ` Alexei Starovoitov
2025-09-01 15:12 ` Leon Hwang
0 siblings, 1 reply; 12+ messages in thread
From: Alexei Starovoitov @ 2025-08-26 22:18 UTC (permalink / raw)
To: Leon Hwang
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard, Song Liu, Yonghong Song,
kernel-patches-bot
On Mon, Aug 25, 2025 at 8:00 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>
>
>
> On 25/8/25 23:17, Alexei Starovoitov wrote:
> > On Mon, Aug 25, 2025 at 6:15 AM Leon Hwang <leon.hwang@linux.dev> wrote:
> >>
> >> Filtering pid_tgid is meaningless when the current task is preempted by
> >> an interrupt.
> >>
> >> To address this, introduce the bpf_in_interrupt kfunc, which allows BPF
> >> programs to determine whether they are executing in interrupt context.
> >>
> >> This enables programs to avoid applying pid_tgid filtering when running
> >> in such contexts.
> >>
> >> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> >> ---
> >> kernel/bpf/helpers.c | 9 +++++++++
> >> kernel/bpf/verifier.c | 11 +++++++++++
> >> 2 files changed, 20 insertions(+)
> >>
> >> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> >> index 401b4932cc49f..38991b7b4a9e9 100644
> >> --- a/kernel/bpf/helpers.c
> >> +++ b/kernel/bpf/helpers.c
> >> @@ -3711,6 +3711,14 @@ __bpf_kfunc int bpf_strstr(const char *s1__ign, const char *s2__ign)
> >> return bpf_strnstr(s1__ign, s2__ign, XATTR_SIZE_MAX);
> >> }
> >>
> >> +/**
> >> + * bpf_in_interrupt - Check whether it's in interrupt context
> >> + */
> >> +__bpf_kfunc int bpf_in_interrupt(void)
> >> +{
> >> + return in_interrupt();
> >> +}
> >
> > It doesn't scale. Next thing people will ask for hard vs soft irq.
> >
>
> How about adding a 'flags'?
>
> Here are the values for 'flags':
>
> * 0: return in_interrupt();
> * 1(NMI): return in_nmi();
> * 2(HARDIRQ): return in_hardirq();
> * 3(SOFTIRQ): return in_softirq();
That's an option, but before we argue whether to do as one kfunc with enum
vs N kfuncs let's explore bpf only option that doesn't involve changing
the kernel.
> >> +#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
> >> + insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
> >
> > I think bpf_per_cpu_ptr() should already be able to read that per cpu var.
> >
>
> Correct. bpf_per_cpu_ptr() and bpf_this_cpu_ptr() are helpful to read it.
Can you add them as static inline functions to bpf_experimental.h
and a selftest to make sure it's all working?
At least for x86 and !PREEMPT_RT.
Like:
bool bpf_in_interrupt()
{
bpf_this_cpu_ptr(...preempt_count..) & (NMI_MASK | HARDIRQ_MASK |
SOFTIRQ_MASK);
}
Of course, there is a danger that kernel implementation might
diverge from bpf-only bit, but it's a risk we're taking all the time.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test bpf_in_interrupt kfunc
2025-08-26 3:05 ` Leon Hwang
@ 2025-08-26 22:31 ` Eduard Zingerman
0 siblings, 0 replies; 12+ messages in thread
From: Eduard Zingerman @ 2025-08-26 22:31 UTC (permalink / raw)
To: Leon Hwang, bpf
Cc: ast, andrii, daniel, martin.lau, song, yonghong.song,
kernel-patches-bot
On Tue, 2025-08-26 at 11:05 +0800, Leon Hwang wrote:
[...]
> > > diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
> > > index 74d912b22de90..65a796fd1d615 100644
> > > --- a/tools/testing/selftests/bpf/progs/irq.c
> > > +++ b/tools/testing/selftests/bpf/progs/irq.c
> > > @@ -563,4 +563,11 @@ int irq_wrong_kfunc_class_2(struct __sk_buff *ctx)
> > > return 0;
> > > }
> > >
> > > +SEC("?tc")
> > > +__success
> >
> > Could you please extend this test to verify generated x86 assembly
> > code? (see __arch_x86_64 and __jited macro usage in verifier_tailcall_jit.c).
>
> I’ll try to extend it, depending on the specific x86 implementation.
>
> > Also, is it necessary to extend this test to actually verify returned
> > value?
>
> Not necessary — let’s just return 0 here.
I mean a bit more broadly, make the bpf program run in an interrupt
and outside of the interrupt context and check the return value.
If it is a small wrapper around existing kernel function probably not
worth it, but you are adding custom logic with inlining.
Basically same thing Alexei asked in the sibling thread.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpf: Introduce bpf_in_interrupt kfunc
2025-08-26 22:18 ` Alexei Starovoitov
@ 2025-09-01 15:12 ` Leon Hwang
2025-09-02 2:29 ` Alexei Starovoitov
0 siblings, 1 reply; 12+ messages in thread
From: Leon Hwang @ 2025-09-01 15:12 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard, Song Liu, Yonghong Song,
kernel-patches-bot
On Wed Aug 27, 2025 at 6:18 AM +08, Alexei Starovoitov wrote:
> On Mon, Aug 25, 2025 at 8:00 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>>
>>
>>
>> On 25/8/25 23:17, Alexei Starovoitov wrote:
>> > On Mon, Aug 25, 2025 at 6:15 AM Leon Hwang <leon.hwang@linux.dev> wrote:
[...]
>> >
>> > It doesn't scale. Next thing people will ask for hard vs soft irq.
>> >
>>
>> How about adding a 'flags'?
>>
>> Here are the values for 'flags':
>>
>> * 0: return in_interrupt();
>> * 1(NMI): return in_nmi();
>> * 2(HARDIRQ): return in_hardirq();
>> * 3(SOFTIRQ): return in_softirq();
>
> That's an option, but before we argue whether to do as one kfunc with enum
> vs N kfuncs let's explore bpf only option that doesn't involve changing
> the kernel.
>
>> >> +#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
>> >> + insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&__preempt_count);
>> >
>> > I think bpf_per_cpu_ptr() should already be able to read that per cpu var.
>> >
>>
>> Correct. bpf_per_cpu_ptr() and bpf_this_cpu_ptr() are helpful to read it.
>
> Can you add them as static inline functions to bpf_experimental.h
> and a selftest to make sure it's all working?
> At least for x86 and !PREEMPT_RT.
> Like:
> bool bpf_in_interrupt()
> {
> bpf_this_cpu_ptr(...preempt_count..) & (NMI_MASK | HARDIRQ_MASK |
> SOFTIRQ_MASK);
> }
>
> Of course, there is a danger that kernel implementation might
> diverge from bpf-only bit, but it's a risk we're taking all the time.
I do a PoC of adding bpf_in_interrupt() to bpf_experimental.h.
It works:
extern bool CONFIG_PREEMPT_RT __kconfig __weak;
#ifdef bpf_target_x86
extern const int __preempt_count __ksym;
#endif
struct task_struct__preempt_rt {
int softirq_disable_cnt;
} __attribute__((preserve_access_index));
/* Description
* Report whether it is in interrupt context. Only works on x86.
*/
static inline int bpf_in_interrupt(void)
{
#ifdef bpf_target_x86
int pcnt;
pcnt = *(int *) bpf_this_cpu_ptr(&__preempt_count);
if (!CONFIG_PREEMPT_RT) {
return pcnt & (NMI_MASK | HARDIRQ_MASK | SOFTIRQ_MASK);
} else {
struct task_struct__preempt_rt *tsk;
tsk = (void *) bpf_get_current_task_btf();
return (pcnt & (NMI_MASK | HARDIRQ_MASK)) |
(tsk->softirq_disable_cnt | SOFTIRQ_MASK);
}
#else
return 0;
#endif
}
However, I only test it for !PREEMPT_RT on x86.
I'd like to respin the patchset by moving bpf_in_interrupt() to
bpf_experimental.h.
Thanks,
Leon
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpf: Introduce bpf_in_interrupt kfunc
2025-09-01 15:12 ` Leon Hwang
@ 2025-09-02 2:29 ` Alexei Starovoitov
2025-09-03 5:22 ` Leon Hwang
0 siblings, 1 reply; 12+ messages in thread
From: Alexei Starovoitov @ 2025-09-02 2:29 UTC (permalink / raw)
To: Leon Hwang
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard, Song Liu, Yonghong Song,
kernel-patches-bot
On Mon, Sep 1, 2025 at 8:12 AM Leon Hwang <leon.hwang@linux.dev> wrote:
>
>
> I do a PoC of adding bpf_in_interrupt() to bpf_experimental.h.
lgtm
> It works:
>
> extern bool CONFIG_PREEMPT_RT __kconfig __weak;
> #ifdef bpf_target_x86
what is bpf_target_x86 ?
> extern const int __preempt_count __ksym;
> #endif
>
> struct task_struct__preempt_rt {
> int softirq_disable_cnt;
> } __attribute__((preserve_access_index));
>
> /* Description
> * Report whether it is in interrupt context. Only works on x86.
arm64 shouldn't be hard to support either.
> */
> static inline int bpf_in_interrupt(void)
> {
> #ifdef bpf_target_x86
> int pcnt;
>
> pcnt = *(int *) bpf_this_cpu_ptr(&__preempt_count);
> if (!CONFIG_PREEMPT_RT) {
> return pcnt & (NMI_MASK | HARDIRQ_MASK | SOFTIRQ_MASK);
> } else {
> struct task_struct__preempt_rt *tsk;
>
> tsk = (void *) bpf_get_current_task_btf();
> return (pcnt & (NMI_MASK | HARDIRQ_MASK)) |
> (tsk->softirq_disable_cnt | SOFTIRQ_MASK);
> }
> #else
> return 0;
> #endif
> }
>
> However, I only test it for !PREEMPT_RT on x86.
>
> I'd like to respin the patchset by moving bpf_in_interrupt() to
> bpf_experimental.h.
I think the approach should work for PREEMPT_RT too.
Test it and send it.
imo this is better than a new kfunc.
Users can start using it right away without waiting for a new kernel.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v2 1/2] bpf: Introduce bpf_in_interrupt kfunc
2025-09-02 2:29 ` Alexei Starovoitov
@ 2025-09-03 5:22 ` Leon Hwang
0 siblings, 0 replies; 12+ messages in thread
From: Leon Hwang @ 2025-09-03 5:22 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard, Song Liu, Yonghong Song,
kernel-patches-bot
On 2/9/25 10:29, Alexei Starovoitov wrote:
> On Mon, Sep 1, 2025 at 8:12 AM Leon Hwang <leon.hwang@linux.dev> wrote:
>>
>>
>> I do a PoC of adding bpf_in_interrupt() to bpf_experimental.h.
>
> lgtm
>
>> It works:
>>
>> extern bool CONFIG_PREEMPT_RT __kconfig __weak;
>> #ifdef bpf_target_x86
>
> what is bpf_target_x86 ?
>
bpf_target_x86 is a macro defined in bpf_tracing.h:
#if defined(__TARGET_ARCH_x86)
#define bpf_target_x86
...
#if defined(__x86_64__)
#define bpf_target_x86
...
>> extern const int __preempt_count __ksym;
>> #endif
>>
>> struct task_struct__preempt_rt {
>> int softirq_disable_cnt;
>> } __attribute__((preserve_access_index));
>>
>> /* Description
>> * Report whether it is in interrupt context. Only works on x86.
>
> arm64 shouldn't be hard to support either.
>
No problem.
I'll add support for arm64.
>> */
>> static inline int bpf_in_interrupt(void)
>> {
>> #ifdef bpf_target_x86
>> int pcnt;
>>
>> pcnt = *(int *) bpf_this_cpu_ptr(&__preempt_count);
>> if (!CONFIG_PREEMPT_RT) {
>> return pcnt & (NMI_MASK | HARDIRQ_MASK | SOFTIRQ_MASK);
>> } else {
>> struct task_struct__preempt_rt *tsk;
>>
>> tsk = (void *) bpf_get_current_task_btf();
>> return (pcnt & (NMI_MASK | HARDIRQ_MASK)) |
>> (tsk->softirq_disable_cnt | SOFTIRQ_MASK);
>> }
>> #else
>> return 0;
>> #endif
>> }
>>
>> However, I only test it for !PREEMPT_RT on x86.
>>
>> I'd like to respin the patchset by moving bpf_in_interrupt() to
>> bpf_experimental.h.
>
> I think the approach should work for PREEMPT_RT too.
> Test it and send it.
Yes, it works for PREEMPT_RT too.
It is able to get retval of bpf_in_interrupt() by running a simple demo.
However, it's really difficult to add selftest case for PREEMPT_RT, as
I'm not familiar with PREEMPT_RT.
Thanks,
Leon
[...]
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-09-03 5:22 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-25 13:14 [PATCH bpf-next v2 0/2] bpf: Introduce bpf_in_interrupt kfunc Leon Hwang
2025-08-25 13:15 ` [PATCH bpf-next v2 1/2] " Leon Hwang
2025-08-25 15:17 ` Alexei Starovoitov
2025-08-26 3:00 ` Leon Hwang
2025-08-26 22:18 ` Alexei Starovoitov
2025-09-01 15:12 ` Leon Hwang
2025-09-02 2:29 ` Alexei Starovoitov
2025-09-03 5:22 ` Leon Hwang
2025-08-25 13:15 ` [PATCH bpf-next v2 2/2] selftests/bpf: Add case to test " Leon Hwang
2025-08-25 17:26 ` Eduard Zingerman
2025-08-26 3:05 ` Leon Hwang
2025-08-26 22:31 ` Eduard Zingerman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).