xdp_has_frags was introduced by the commit
c2f2cdbeffda ("bpf: introduce BPF_F_XDP_HAS_FRAGS flag in prog_flags loading the ebpf program").
The commit f45d5b6ce2e8 ("bpf: generalise tail call map compatibility check")
was to ensure backwards compatibility against tail calls. However, it
missed that XDP progs can be extended by freplace progs, which could break
the backwards compatibility, e.g. xdp_has_frags=true freplace progs are
allowed to attach to xdp_has_frags=false XDP progs.
To avoid breaking the backwards compatibility via freplace, disallow
freplace on XDP programs with different xdp_has_frags values.
Cc: Toke Hoiland-Jorgensen <toke@redhat.com>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: Lorenzo Bianconi <lorenzo@kernel.org>
Fixes: c2f2cdbeffda ("bpf: introduce BPF_F_XDP_HAS_FRAGS flag in prog_flags loading the ebpf program")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
kernel/bpf/verifier.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index cd008b146ee5..12330466d58b 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -25519,6 +25519,10 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
*/
env->ops = bpf_verifier_ops[tgt_prog->type];
prog->expected_attach_type = tgt_prog->expected_attach_type;
+ if (prog->aux->xdp_has_frags != tgt_prog->aux->xdp_has_frags) {
+ verbose(env, "Extension program cannot have different xdp_has_frags value with target prog\n");
+ return -EINVAL;
+ }
}
/* store info about the attachment target that will be used later */
--
2.53.0
On Tue, 24 Mar 2026 23:04:42 +0800 Leon Hwang wrote:
> The commit f45d5b6ce2e8 ("bpf: generalise tail call map compatibility check")
> was to ensure backwards compatibility against tail calls. However, it
> missed that XDP progs can be extended by freplace progs, which could break
> the backwards compatibility, e.g. xdp_has_frags=true freplace progs are
> allowed to attach to xdp_has_frags=false XDP progs.
>
> To avoid breaking the backwards compatibility via freplace, disallow
> freplace on XDP programs with different xdp_has_frags values.
It may be worth adding a selftest to
tools/testing/selftests/drivers/net/xdp.py
which sets MTU to 9k, tries to attach a non-frag-capable prog
if that fails attaches a frag-capable prog and then checks if
replacing the capable prog with non-capable fails.
Drivers may be buggy in this regard.
On 27/3/26 03:42, Jakub Kicinski wrote:
> On Tue, 24 Mar 2026 23:04:42 +0800 Leon Hwang wrote:
>> The commit f45d5b6ce2e8 ("bpf: generalise tail call map compatibility check")
>> was to ensure backwards compatibility against tail calls. However, it
>> missed that XDP progs can be extended by freplace progs, which could break
>> the backwards compatibility, e.g. xdp_has_frags=true freplace progs are
>> allowed to attach to xdp_has_frags=false XDP progs.
>>
>> To avoid breaking the backwards compatibility via freplace, disallow
>> freplace on XDP programs with different xdp_has_frags values.
>
> It may be worth adding a selftest to
> tools/testing/selftests/drivers/net/xdp.py
> which sets MTU to 9k, tries to attach a non-frag-capable prog
> if that fails attaches a frag-capable prog and then checks if
> replacing the capable prog with non-capable fails.
> Drivers may be buggy in this regard.
Do you mean adding these two tests to xdp.py?
1. Verify the failure of attaching non-frag-capable prog to mtu=9k
driver.
2. Verify the failure of updating frag-capable prog with non-frag-
capable prog via libbpf.c::bpf_link__update_program().
As for test #2, it may require a helper to attach prog then update prog
using libbpf's APIs.
Thanks,
Leon
On Fri, 27 Mar 2026 14:42:19 +0800 Leon Hwang wrote: > > It may be worth adding a selftest to > > tools/testing/selftests/drivers/net/xdp.py > > which sets MTU to 9k, tries to attach a non-frag-capable prog > > if that fails attaches a frag-capable prog and then checks if > > replacing the capable prog with non-capable fails. > > Drivers may be buggy in this regard. > > Do you mean adding these two tests to xdp.py? > > 1. Verify the failure of attaching non-frag-capable prog to mtu=9k > driver. > 2. Verify the failure of updating frag-capable prog with non-frag- > capable prog via libbpf.c::bpf_link__update_program(). Not directly via libbpf just ip -f link, it uses libbpf internally but testing with ip link is simpler. Also - there are already XDP progs which return XDP_PASS in frag-capable and non-capable mode, so just use those. > As for test #2, it may require a helper to attach prog then update prog > using libbpf's APIs. See above.
On 28/3/26 08:12, Jakub Kicinski wrote:
> On Fri, 27 Mar 2026 14:42:19 +0800 Leon Hwang wrote:
>>> It may be worth adding a selftest to
>>> tools/testing/selftests/drivers/net/xdp.py
>>> which sets MTU to 9k, tries to attach a non-frag-capable prog
>>> if that fails attaches a frag-capable prog and then checks if
>>> replacing the capable prog with non-capable fails.
>>> Drivers may be buggy in this regard.
>>
>> Do you mean adding these two tests to xdp.py?
>>
>> 1. Verify the failure of attaching non-frag-capable prog to mtu=9k
>> driver.
>> 2. Verify the failure of updating frag-capable prog with non-frag-
>> capable prog via libbpf.c::bpf_link__update_program().
>
> Not directly via libbpf just ip -f link, it uses libbpf internally
> but testing with ip link is simpler. Also - there are already XDP
> progs which return XDP_PASS in frag-capable and non-capable mode,
> so just use those.
>
Yep, I see these XDP progs in xdp_dummy.bpf.c.
I think the option of ip cmd to update XDP prog is -force.
# ip l set dev eth0 mtu 9000
# ip l set dev eth0 xdpdrv obj xdp_dummy.bpf.o sec xdp.frags
# ip l
6: eth0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 9000 xdp qdisc mq
master bond0 state UP mode DEFAULT group default qlen 1000
link/ether 3a:39:5f:35:17:6c brd ff:ff:ff:ff:ff:ff permaddr
e0:9d:73:c6:7a:d6
prog/xdp id 72 name xdp_dummy_prog_ tag 614b434cd8324ecc jited
# ip -force l set dev eth0 xdpdrv obj xdp_dummy.bpf.o sec xdp.frags
# ip l
6: eth0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 9000 xdp qdisc mq
master bond0 state UP mode DEFAULT group default qlen 1000
link/ether 3a:39:5f:35:17:6c brd ff:ff:ff:ff:ff:ff permaddr
e0:9d:73:c6:7a:d6
prog/xdp id 76 name xdp_dummy_prog_ tag 614b434cd8324ecc jited
# ip l set dev eth0 mtu 1500 xdpdrv off
I'd like to post an RFC to net-next later.
Thanks,
Leon
Leon Hwang <leon.hwang@linux.dev> writes:
> xdp_has_frags was introduced by the commit
> c2f2cdbeffda ("bpf: introduce BPF_F_XDP_HAS_FRAGS flag in prog_flags loading the ebpf program").
>
> The commit f45d5b6ce2e8 ("bpf: generalise tail call map compatibility check")
> was to ensure backwards compatibility against tail calls. However, it
> missed that XDP progs can be extended by freplace progs, which could break
> the backwards compatibility, e.g. xdp_has_frags=true freplace progs are
> allowed to attach to xdp_has_frags=false XDP progs.
>
> To avoid breaking the backwards compatibility via freplace, disallow
> freplace on XDP programs with different xdp_has_frags values.
The problem you describe is not actually a problem, though? A
frags-aware program can run on a non-frags interface just fine.
You're messing with long-standing behaviour (since 5.18!) to solve a
non-existent problem. In a way that completely breaks the frags handling
in libxdp[0]:
Running tests from ./test-libxdp.sh
[test_link_so] PASS
[test_link_a] PASS
[test_old_dispatcher] PASS
[test_xdp_devbound] PASS
[test_xdp_frags] FAIL
Kernel supports XDP programs with frags
check_load_frags: FAILED
check_load_nofrags_success: PASSED
check_load_nofrags_fail: PASSED
check_load_frags_multi: FAILED
check_load_mix_big: FAILED
check_load_mix_small: FAILED
Test test_xdp_frags exited with return code: 1
Please don't do that.
-Toke
[0] Run 'make test' here: https://github.com/xdp-project/xdp-tools
On 25/3/26 00:18, Toke Høiland-Jørgensen wrote:
> Leon Hwang <leon.hwang@linux.dev> writes:
>
>> xdp_has_frags was introduced by the commit
>> c2f2cdbeffda ("bpf: introduce BPF_F_XDP_HAS_FRAGS flag in prog_flags loading the ebpf program").
>>
>> The commit f45d5b6ce2e8 ("bpf: generalise tail call map compatibility check")
>> was to ensure backwards compatibility against tail calls. However, it
>> missed that XDP progs can be extended by freplace progs, which could break
>> the backwards compatibility, e.g. xdp_has_frags=true freplace progs are
>> allowed to attach to xdp_has_frags=false XDP progs.
>>
>> To avoid breaking the backwards compatibility via freplace, disallow
>> freplace on XDP programs with different xdp_has_frags values.
>
> The problem you describe is not actually a problem, though? A
> frags-aware program can run on a non-frags interface just fine.
>
> You're messing with long-standing behaviour (since 5.18!) to solve a
> non-existent problem. In a way that completely breaks the frags handling
> in libxdp[0]:
>
> Running tests from ./test-libxdp.sh
> [test_link_so] PASS
> [test_link_a] PASS
> [test_old_dispatcher] PASS
> [test_xdp_devbound] PASS
> [test_xdp_frags] FAIL
> Kernel supports XDP programs with frags
> check_load_frags: FAILED
> check_load_nofrags_success: PASSED
> check_load_nofrags_fail: PASSED
> check_load_frags_multi: FAILED
> check_load_mix_big: FAILED
> check_load_mix_small: FAILED
> Test test_xdp_frags exited with return code: 1
>
>
> Please don't do that.
>
> -Toke
>
> [0] Run 'make test' here: https://github.com/xdp-project/xdp-tools
>
Indeed, it failed to 'make test'.
Will drop this patch in v2, as it wasn't an issue.
Thanks,
Leon
Leon Hwang <leon.hwang@linux.dev> writes:
> On 25/3/26 00:18, Toke Høiland-Jørgensen wrote:
>> Leon Hwang <leon.hwang@linux.dev> writes:
>>
>>> xdp_has_frags was introduced by the commit
>>> c2f2cdbeffda ("bpf: introduce BPF_F_XDP_HAS_FRAGS flag in prog_flags loading the ebpf program").
>>>
>>> The commit f45d5b6ce2e8 ("bpf: generalise tail call map compatibility check")
>>> was to ensure backwards compatibility against tail calls. However, it
>>> missed that XDP progs can be extended by freplace progs, which could break
>>> the backwards compatibility, e.g. xdp_has_frags=true freplace progs are
>>> allowed to attach to xdp_has_frags=false XDP progs.
>>>
>>> To avoid breaking the backwards compatibility via freplace, disallow
>>> freplace on XDP programs with different xdp_has_frags values.
>>
>> The problem you describe is not actually a problem, though? A
>> frags-aware program can run on a non-frags interface just fine.
>>
>> You're messing with long-standing behaviour (since 5.18!) to solve a
>> non-existent problem. In a way that completely breaks the frags handling
>> in libxdp[0]:
>>
>> Running tests from ./test-libxdp.sh
>> [test_link_so] PASS
>> [test_link_a] PASS
>> [test_old_dispatcher] PASS
>> [test_xdp_devbound] PASS
>> [test_xdp_frags] FAIL
>> Kernel supports XDP programs with frags
>> check_load_frags: FAILED
>> check_load_nofrags_success: PASSED
>> check_load_nofrags_fail: PASSED
>> check_load_frags_multi: FAILED
>> check_load_mix_big: FAILED
>> check_load_mix_small: FAILED
>> Test test_xdp_frags exited with return code: 1
>>
>>
>> Please don't do that.
>>
>> -Toke
>>
>> [0] Run 'make test' here: https://github.com/xdp-project/xdp-tools
>>
>
> Indeed, it failed to 'make test'.
>
> Will drop this patch in v2, as it wasn't an issue.
Great, thanks!
-Toke
© 2016 - 2026 Red Hat, Inc.