bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).