On Fri, Oct 17, 2025 at 04:46:48PM +0200, Tomas Glozar wrote:
> Add option --bpf-action that allows the user to attach an external BPF
> program that will be executed via BPF tail call on latency threshold
> overflow.
> 
> Executing additional BPF code on latency threshold overflow allows doing
> doing low-latency and in-kernel troubleshooting of the cause of the
> overflow.
> 
> The option takes an argument, which is a path to a BPF ELF file
> expected to contain a function named "action_handler" in a section named
> "tp/timerlat_action" (the section is necessary for libbpf to asssign the
> correct BPF program type to it).
> 
> Signed-off-by: Tomas Glozar <[email protected]>
> ---
>  tools/tracing/rtla/src/timerlat.c      | 11 ++++++
>  tools/tracing/rtla/src/timerlat.h      |  2 +-
>  tools/tracing/rtla/src/timerlat_bpf.c  | 54 ++++++++++++++++++++++++++
>  tools/tracing/rtla/src/timerlat_bpf.h  |  6 ++-
>  tools/tracing/rtla/src/timerlat_hist.c |  5 +++
>  tools/tracing/rtla/src/timerlat_top.c  |  5 +++
>  6 files changed, 81 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/tracing/rtla/src/timerlat.c 
> b/tools/tracing/rtla/src/timerlat.c
> index b69212874127..6907a323f9ec 100644
> --- a/tools/tracing/rtla/src/timerlat.c
> +++ b/tools/tracing/rtla/src/timerlat.c
> @@ -48,6 +48,17 @@ timerlat_apply_config(struct osnoise_tool *tool, struct 
> timerlat_params *params)
>               }
>       }
>  
> +     /* Check if BPF action program is requested but BPF is not available */
> +     if (params->bpf_action_program) {
> +             if (params->mode == TRACING_MODE_TRACEFS) {
> +                     err_msg("BPF actions are not supported in tracefs-only 
> mode\n");
> +                     goto out_err;
> +             }
> +
> +             if 
> (timerlat_load_bpf_action_program(params->bpf_action_program))
> +                     goto out_err;
> +     }
> +
>       if (params->mode != TRACING_MODE_BPF) {
>               /*
>                * In tracefs and mixed mode, timerlat tracer handles stopping
> diff --git a/tools/tracing/rtla/src/timerlat.h 
> b/tools/tracing/rtla/src/timerlat.h
> index fd6065f48bb7..8dd5d134ce08 100644
> --- a/tools/tracing/rtla/src/timerlat.h
> +++ b/tools/tracing/rtla/src/timerlat.h
> @@ -27,6 +27,7 @@ struct timerlat_params {
>       int                     dump_tasks;
>       int                     deepest_idle_state;
>       enum timerlat_tracing_mode mode;
> +     const char              *bpf_action_program;
>  };
>  
>  #define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, 
> common)
> @@ -36,4 +37,3 @@ int timerlat_main(int argc, char *argv[]);
>  int timerlat_enable(struct osnoise_tool *tool);
>  void timerlat_analyze(struct osnoise_tool *tool, bool stopped);
>  void timerlat_free(struct osnoise_tool *tool);
> -
> diff --git a/tools/tracing/rtla/src/timerlat_bpf.c 
> b/tools/tracing/rtla/src/timerlat_bpf.c
> index 1d619e502c65..3c63bf7aa607 100644
> --- a/tools/tracing/rtla/src/timerlat_bpf.c
> +++ b/tools/tracing/rtla/src/timerlat_bpf.c
> @@ -7,6 +7,10 @@
>  
>  static struct timerlat_bpf *bpf;
>  
> +/* BPF object and program for action program */
> +static struct bpf_object *obj;
> +static struct bpf_program *prog;
> +
>  /*
>   * timerlat_bpf_init - load and initialize BPF program to collect timerlat 
> data
>   */
> @@ -56,6 +60,10 @@ int timerlat_bpf_init(struct timerlat_params *params)
>               return err;
>       }
>  
> +     /* Set BPF action program to NULL */
> +     prog = NULL;
> +     obj = NULL;
> +
>       return 0;
>  }
>  
> @@ -96,6 +104,11 @@ void timerlat_bpf_detach(void)
>  void timerlat_bpf_destroy(void)
>  {
>       timerlat_bpf__destroy(bpf);
> +     bpf = NULL;
> +     if (obj)
> +             bpf_object__close(obj);
> +     obj = NULL;
> +     prog = NULL;
>  }
>  
>  static int handle_rb_event(void *ctx, void *data, size_t data_sz)
> @@ -190,4 +203,45 @@ int timerlat_bpf_get_summary_value(enum summary_field 
> key,
>                        bpf->maps.summary_user,
>                        key, value_irq, value_thread, value_user, cpus);
>  }
> +
> +/*
> + * timerlat_load_bpf_action_program - load and register a BPF action program
> + */
> +int timerlat_load_bpf_action_program(const char *program_path)
> +{
> +     int err;
> +
> +     obj = bpf_object__open_file(program_path, NULL);
> +     if (!obj) {
> +             err_msg("Failed to open BPF action program: %s\n", 
> program_path);
> +             return -1;
> +     }
> +
> +     err = bpf_object__load(obj);
> +     if (err) {
> +             err_msg("Failed to load BPF action program: %s\n", 
> program_path);

This error path misses the call to to bpf_object__close()

> +             return -1;
> +     }
> +
> +     prog = bpf_object__find_program_by_name(obj, "action_handler");
> +     if (!prog) {
> +             err_msg("BPF action program must have 'action_handler' 
> function: %s\n",
> +                     program_path);
> +             bpf_object__close(obj);
> +             obj = NULL;
> +             return -1;
> +     }
> +
> +     err = timerlat_bpf_set_action(prog);
> +     if (err) {
> +             err_msg("Failed to register BPF action program: %s\n", 
> program_path);
> +             bpf_object__close(obj);
> +             obj = NULL;
> +             prog = NULL;
> +             return -1;
> +     }
> +
> +     return 0;
> +}
> +
>  #endif /* HAVE_BPF_SKEL */
> diff --git a/tools/tracing/rtla/src/timerlat_bpf.h 
> b/tools/tracing/rtla/src/timerlat_bpf.h
> index b5009092c7a3..169abeaf4363 100644
> --- a/tools/tracing/rtla/src/timerlat_bpf.h
> +++ b/tools/tracing/rtla/src/timerlat_bpf.h
> @@ -30,7 +30,7 @@ int timerlat_bpf_get_summary_value(enum summary_field key,
>                                  long long *value_thread,
>                                  long long *value_user,
>                                  int cpus);
> -
> +int timerlat_load_bpf_action_program(const char *program_path);
>  static inline int have_libbpf_support(void) { return 1; }
>  #else
>  static inline int timerlat_bpf_init(struct timerlat_params *params)
> @@ -58,6 +58,10 @@ static inline int timerlat_bpf_get_summary_value(enum 
> summary_field key,
>  {
>       return -1;
>  }
> +static inline int timerlat_load_bpf_action_program(const char *program_path)
> +{
> +     return -1;
> +}
>  static inline int have_libbpf_support(void) { return 0; }
>  #endif /* HAVE_BPF_SKEL */
>  #endif /* __bpf__ */
> diff --git a/tools/tracing/rtla/src/timerlat_hist.c 
> b/tools/tracing/rtla/src/timerlat_hist.c
> index 606c1688057b..5e639cc34f64 100644
> --- a/tools/tracing/rtla/src/timerlat_hist.c
> +++ b/tools/tracing/rtla/src/timerlat_hist.c
> @@ -763,6 +763,7 @@ static void timerlat_hist_usage(char *usage)
>               "            --deepest-idle-state n: only go down to idle state 
> n on cpus used by timerlat to reduce exit from idle latency",
>               "            --on-threshold <action>: define action to be 
> executed at latency threshold, multiple are allowed",
>               "            --on-end <action>: define action to be executed at 
> measurement end, multiple are allowed",
> +             "            --bpf-action <program>: load and execute BPF 
> program when latency threshold is exceeded",
>               NULL,
>       };
>  
> @@ -853,6 +854,7 @@ static struct common_params
>                       {"deepest-idle-state",  required_argument,      0, 
> '\4'},
>                       {"on-threshold",        required_argument,      0, 
> '\5'},
>                       {"on-end",              required_argument,      0, 
> '\6'},
> +                     {"bpf-action",          required_argument,      0, 
> '\7'},
>                       {0, 0, 0, 0}
>               };
>  
> @@ -1062,6 +1064,9 @@ static struct common_params
>                               exit(EXIT_FAILURE);
>                       }
>                       break;
> +             case '\7':
> +                     params->bpf_action_program = optarg;
> +                     break;
>               default:
>                       timerlat_hist_usage("Invalid option");
>               }
> diff --git a/tools/tracing/rtla/src/timerlat_top.c 
> b/tools/tracing/rtla/src/timerlat_top.c
> index fc479a0dcb59..da5d5db1bc17 100644
> --- a/tools/tracing/rtla/src/timerlat_top.c
> +++ b/tools/tracing/rtla/src/timerlat_top.c
> @@ -521,6 +521,7 @@ static void timerlat_top_usage(char *usage)
>               "            --deepest-idle-state n: only go down to idle state 
> n on cpus used by timerlat to reduce exit from idle latency",
>               "            --on-threshold <action>: define action to be 
> executed at latency threshold, multiple are allowed",
>               "            --on-end: define action to be executed at 
> measurement end, multiple are allowed",
> +             "            --bpf-action <program>: load and execute BPF 
> program when latency threshold is exceeded",
>               NULL,
>       };
>  
> @@ -603,6 +604,7 @@ static struct common_params
>                       {"deepest-idle-state",  required_argument,      0, '8'},
>                       {"on-threshold",        required_argument,      0, '9'},
>                       {"on-end",              required_argument,      0, 
> '\1'},
> +                     {"bpf-action",          required_argument,      0, 
> '\2'},
>                       {0, 0, 0, 0}
>               };
>  
> @@ -798,6 +800,9 @@ static struct common_params
>                               exit(EXIT_FAILURE);
>                       }
>                       break;
> +             case '\2':
> +                     params->bpf_action_program = optarg;
> +                     break;
>               default:
>                       timerlat_top_usage("Invalid option");
>               }
> -- 
> 2.51.0
> 


Reply via email to