To support the extended BPF syscall introduced in the previous commit,
introduce the following internal APIs:
* 'sys_bpf_ext()'
* 'sys_bpf_ext_fd()'
They wrap the raw 'syscall()' interface to support passing extended
attributes.
* 'probe_sys_bpf_ext()'
Check whether current kernel supports the BPF syscall common attributes.
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
tools/lib/bpf/bpf.c | 36 +++++++++++++++++++++++++++++++++
tools/lib/bpf/features.c | 11 ++++++++++
tools/lib/bpf/libbpf_internal.h | 3 +++
3 files changed, 50 insertions(+)
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 21b57a629916..fc87552b1378 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -69,6 +69,42 @@ static inline __u64 ptr_to_u64(const void *ptr)
return (__u64) (unsigned long) ptr;
}
+static inline int sys_bpf_ext(enum bpf_cmd cmd, union bpf_attr *attr,
+ unsigned int size,
+ struct bpf_common_attr *attr_common,
+ unsigned int size_common)
+{
+ cmd = attr_common ? (cmd | BPF_COMMON_ATTRS) : (cmd & ~BPF_COMMON_ATTRS);
+ return syscall(__NR_bpf, cmd, attr, size, attr_common, size_common);
+}
+
+static inline int sys_bpf_ext_fd(enum bpf_cmd cmd, union bpf_attr *attr,
+ unsigned int size,
+ struct bpf_common_attr *attr_common,
+ unsigned int size_common)
+{
+ int fd;
+
+ fd = sys_bpf_ext(cmd, attr, size, attr_common, size_common);
+ return ensure_good_fd(fd);
+}
+
+int probe_sys_bpf_ext(void)
+{
+ const size_t attr_sz = offsetofend(union bpf_attr, prog_token_fd);
+ union bpf_attr attr;
+ int fd;
+
+ memset(&attr, 0, attr_sz);
+ fd = syscall(__NR_bpf, BPF_PROG_LOAD | BPF_COMMON_ATTRS, &attr, attr_sz, NULL,
+ sizeof(struct bpf_common_attr));
+ if (fd >= 0) {
+ close(fd);
+ return -EINVAL;
+ }
+ return errno == EFAULT ? 1 : -errno;
+}
+
static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
unsigned int size)
{
diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c
index b842b83e2480..e82c2afead43 100644
--- a/tools/lib/bpf/features.c
+++ b/tools/lib/bpf/features.c
@@ -506,6 +506,14 @@ static int probe_kern_arg_ctx_tag(int token_fd)
return probe_fd(prog_fd);
}
+static int probe_bpf_syscall_common_attrs(int token_fd)
+{
+ int ret;
+
+ ret = probe_sys_bpf_ext();
+ return ret > 0;
+}
+
typedef int (*feature_probe_fn)(int /* token_fd */);
static struct kern_feature_cache feature_cache;
@@ -581,6 +589,9 @@ static struct kern_feature_desc {
[FEAT_BTF_QMARK_DATASEC] = {
"BTF DATASEC names starting from '?'", probe_kern_btf_qmark_datasec,
},
+ [FEAT_BPF_SYSCALL_COMMON_ATTRS] = {
+ "BPF syscall common attributes support", probe_bpf_syscall_common_attrs,
+ },
};
bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index fc59b21b51b5..aa16be869c4f 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -392,6 +392,8 @@ enum kern_feature_id {
FEAT_ARG_CTX_TAG,
/* Kernel supports '?' at the front of datasec names */
FEAT_BTF_QMARK_DATASEC,
+ /* Kernel supports BPF syscall common attributes */
+ FEAT_BPF_SYSCALL_COMMON_ATTRS,
__FEAT_CNT,
};
@@ -757,4 +759,5 @@ int probe_fd(int fd);
#define SHA256_DWORD_SIZE SHA256_DIGEST_LENGTH / sizeof(__u64)
void libbpf_sha256(const void *data, size_t len, __u8 out[SHA256_DIGEST_LENGTH]);
+int probe_sys_bpf_ext(void);
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */
--
2.52.0
On Thu, Jan 22, 2026 at 7:25 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>
>
> +static int probe_bpf_syscall_common_attrs(int token_fd)
> +{
> + int ret;
> +
> + ret = probe_sys_bpf_ext();
> + return ret > 0;
> +}
When you look at the above, what thoughts come to mind?
... and please don't use ai for answers.
On 23/1/26 11:55, Alexei Starovoitov wrote:
> On Thu, Jan 22, 2026 at 7:25 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>>
>>
>> +static int probe_bpf_syscall_common_attrs(int token_fd)
>> +{
>> + int ret;
>> +
>> + ret = probe_sys_bpf_ext();
>> + return ret > 0;
>> +}
>
> When you look at the above, what thoughts come to mind?
>
> ... and please don't use ai for answers.
My initial thought was whether probe_fd() is needed here to handle and
close a returned fd, since the return value of probe_sys_bpf_ext() isn’t
obvious from the call site.
Thanks,
Leon
On Thu, Jan 22, 2026 at 8:07 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>
>
>
> On 23/1/26 11:55, Alexei Starovoitov wrote:
> > On Thu, Jan 22, 2026 at 7:25 PM Leon Hwang <leon.hwang@linux.dev> wrote:
> >>
> >>
> >> +static int probe_bpf_syscall_common_attrs(int token_fd)
> >> +{
> >> + int ret;
> >> +
> >> + ret = probe_sys_bpf_ext();
> >> + return ret > 0;
> >> +}
> >
> > When you look at the above, what thoughts come to mind?
> >
> > ... and please don't use ai for answers.
>
> My initial thought was whether probe_fd() is needed here to handle and
> close a returned fd, since the return value of probe_sys_bpf_ext() isn’t
> obvious from the call site.
Fair enough, but then collapse it into one helper if FD is a concern.
My question was about stylistic/taste preferences.
On 23/1/26 12:12, Alexei Starovoitov wrote:
> On Thu, Jan 22, 2026 at 8:07 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>>
>>
>>
>> On 23/1/26 11:55, Alexei Starovoitov wrote:
>>> On Thu, Jan 22, 2026 at 7:25 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>>>>
>>>>
>>>> +static int probe_bpf_syscall_common_attrs(int token_fd)
>>>> +{
>>>> + int ret;
>>>> +
>>>> + ret = probe_sys_bpf_ext();
>>>> + return ret > 0;
>>>> +}
>>>
>>> When you look at the above, what thoughts come to mind?
>>>
>>> ... and please don't use ai for answers.
>>
>> My initial thought was whether probe_fd() is needed here to handle and
>> close a returned fd, since the return value of probe_sys_bpf_ext() isn’t
>> obvious from the call site.
>
> Fair enough, but then collapse it into one helper if FD is a concern.
> My question was about stylistic/taste preferences.
Understood, thanks for the clarification.
I’ll rework it with the stylistic preference in mind.
Thanks,
Leon
On Thu, Jan 22, 2026 at 8:19 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>
>
>
> On 23/1/26 12:12, Alexei Starovoitov wrote:
> > On Thu, Jan 22, 2026 at 8:07 PM Leon Hwang <leon.hwang@linux.dev> wrote:
> >>
> >>
> >>
> >> On 23/1/26 11:55, Alexei Starovoitov wrote:
> >>> On Thu, Jan 22, 2026 at 7:25 PM Leon Hwang <leon.hwang@linux.dev> wrote:
> >>>>
> >>>>
> >>>> +static int probe_bpf_syscall_common_attrs(int token_fd)
> >>>> +{
> >>>> + int ret;
> >>>> +
> >>>> + ret = probe_sys_bpf_ext();
> >>>> + return ret > 0;
> >>>> +}
> >>>
> >>> When you look at the above, what thoughts come to mind?
> >>>
> >>> ... and please don't use ai for answers.
> >>
> >> My initial thought was whether probe_fd() is needed here to handle and
> >> close a returned fd, since the return value of probe_sys_bpf_ext() isn’t
> >> obvious from the call site.
Have you looked at how probes are called (in feat_supported()?) They
all follow the same contract: > 0 (normally just 1) means feature is
supported, 0 means feature is not supported, and <0 means something
went wrong. Libbpf will log an error and will assume feature is not
supported.
probe_sys_bpf_ext() should either follow that convention or drop the
probe_ prefix altogether to avoid confusion. And then
probe_bpf_syscall_common_attrs() is necessary only as a wrapper around
probe_sys_bpf_ext() to ignore mandatory (but unused) token_fd argument
(so to make it "pluggable" into feat_supported() framework).
So, just make probe_sys_bpf_ext() follow probe contract as described,
and then just:
static int probe_bpf_syscall_common_attr(int token_fd)
{
return probe_sys_bpf_ext();
}
Alternatively, just make probe_sys_bpf_ext() take token_fd (but ignore
it), and just use probe_sys_bpf_ext() directly for feat_supported().
probe_fd() is not suitable here because it's for a common case when we
expect syscall to succeed and create fd, in which case that successful
fd represents successful feature detection. This is not the case here,
so probe_fd() is not what you should use.
> >
> > Fair enough, but then collapse it into one helper if FD is a concern.
> > My question was about stylistic/taste preferences.
>
> Understood, thanks for the clarification.
>
> I’ll rework it with the stylistic preference in mind.
>
> Thanks,
> Leon
>
On 24/1/26 02:52, Andrii Nakryiko wrote:
> On Thu, Jan 22, 2026 at 8:19 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>>
>>
>>
>> On 23/1/26 12:12, Alexei Starovoitov wrote:
>>> On Thu, Jan 22, 2026 at 8:07 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>>>>
>>>>
>>>>
>>>> On 23/1/26 11:55, Alexei Starovoitov wrote:
>>>>> On Thu, Jan 22, 2026 at 7:25 PM Leon Hwang <leon.hwang@linux.dev> wrote:
>>>>>>
>>>>>>
>>>>>> +static int probe_bpf_syscall_common_attrs(int token_fd)
>>>>>> +{
>>>>>> + int ret;
>>>>>> +
>>>>>> + ret = probe_sys_bpf_ext();
>>>>>> + return ret > 0;
>>>>>> +}
>>>>>
>>>>> When you look at the above, what thoughts come to mind?
>>>>>
>>>>> ... and please don't use ai for answers.
>>>>
>>>> My initial thought was whether probe_fd() is needed here to handle and
>>>> close a returned fd, since the return value of probe_sys_bpf_ext() isn’t
>>>> obvious from the call site.
>
> Have you looked at how probes are called (in feat_supported()?) They
> all follow the same contract: > 0 (normally just 1) means feature is
> supported, 0 means feature is not supported, and <0 means something
> went wrong. Libbpf will log an error and will assume feature is not
> supported.
>
I’ve looked at feat_supported().
Even though I was aware of the probe contract, I should have thought it
through more carefully in the context of feat_supported() and
probe_sys_bpf_ext(). With that in mind, your suggestion makes sense now.
> probe_sys_bpf_ext() should either follow that convention or drop the
> probe_ prefix altogether to avoid confusion. And then
> probe_bpf_syscall_common_attrs() is necessary only as a wrapper around
> probe_sys_bpf_ext() to ignore mandatory (but unused) token_fd argument
> (so to make it "pluggable" into feat_supported() framework).
>
> So, just make probe_sys_bpf_ext() follow probe contract as described,
> and then just:
>
> static int probe_bpf_syscall_common_attr(int token_fd)
> {
> return probe_sys_bpf_ext();
> }
>
I’ll make probe_sys_bpf_ext() follow the standard probe convention, and
keep probe_bpf_syscall_common_attrs() as a thin wrapper to ignore the
mandatory (but unused) token_fd argument, so it plugs cleanly into
feat_supported() framework.
> Alternatively, just make probe_sys_bpf_ext() take token_fd (but ignore
> it), and just use probe_sys_bpf_ext() directly for feat_supported().
>
>
> probe_fd() is not suitable here because it's for a common case when we
> expect syscall to succeed and create fd, in which case that successful
> fd represents successful feature detection. This is not the case here,
> so probe_fd() is not what you should use.
>
Agreed as well that probe_fd() is not suitable here, since this probe is
not expected to return a successful FD.
Thanks for the detailed explanation.
Thanks,
Leon
>>>
>>> Fair enough, but then collapse it into one helper if FD is a concern.
>>> My question was about stylistic/taste preferences.
>>
>> Understood, thanks for the clarification.
>>
>> I’ll rework it with the stylistic preference in mind.
>>
>> Thanks,
>> Leon
>>
© 2016 - 2026 Red Hat, Inc.