[RFC PATCH bpf-next v1 1/7] xdp: let XDP programs assert the RX checksum over redirect
From: Vladimir Vdovin <hidden>
Date: 2026-06-30 19:17:56
Also in:
bpf
Subsystem:
networking [general], the rest, xdp (express data path) · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Alexei Starovoitov, Daniel Borkmann, David S. Miller, Jesper Dangaard Brouer, John Fastabend
When an XDP program redirects a frame to a cpumap (or any other path that rebuilds an skb from an xdp_frame via __xdp_build_skb_from_frame()), the HW RX checksum status is lost and the stack revalidates the L4 checksum in software. Add a non-dev-bound kfunc, bpf_xdp_assert_rx_csum(), that lets the program assert the L4 checksum is correct. It sets XDP_FLAGS_RX_CSUM_UNNECESSARY on the buffer; the flag rides into the xdp_frame and __xdp_build_skb_from_frame() turns it into skb->ip_summed = CHECKSUM_UNNECESSARY. The kernel cannot verify the assertion, the program takes responsibility, the same way it is already trusted to rewrite arbitrary packet contents. Signed-off-by: Vladimir Vdovin <redacted> --- include/net/xdp.h | 11 +++++++++++ net/core/xdp.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/include/net/xdp.h b/include/net/xdp.h
index aa742f413c35..5a1e2cc9c312 100644
--- a/include/net/xdp.h
+++ b/include/net/xdp.h@@ -81,6 +81,11 @@ enum xdp_buff_flags { * XDP program is not attached. */ XDP_FLAGS_FRAGS_UNREADABLE = BIT(2), + /* XDP program asserts the L4 checksum is correct, so the skb built + * out of this frame (e.g. on the cpumap redirect path) can be marked + * CHECKSUM_UNNECESSARY instead of being validated in software. + */ + XDP_FLAGS_RX_CSUM_UNNECESSARY = BIT(3), }; struct xdp_buff {
@@ -316,6 +321,12 @@ xdp_frame_get_skb_flags(const struct xdp_frame *frame) return frame->flags; } +static __always_inline bool +xdp_frame_rx_csum_unnecessary(const struct xdp_frame *frame) +{ + return !!(frame->flags & XDP_FLAGS_RX_CSUM_UNNECESSARY); +} + #define XDP_BULK_QUEUE_SIZE 16 struct xdp_frame_bulk { int count;
diff --git a/net/core/xdp.c b/net/core/xdp.c
index 9890a30584ba..63ee36ec93de 100644
--- a/net/core/xdp.c
+++ b/net/core/xdp.c@@ -830,8 +830,11 @@ struct sk_buff *__xdp_build_skb_from_frame(struct xdp_frame *xdpf, /* Essential SKB info: protocol and skb->dev */ skb->protocol = eth_type_trans(skb, dev); + /* HW checksum info, if the XDP program asserted it */ + if (xdp_frame_rx_csum_unnecessary(xdpf)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + /* Optional SKB info, currently missing: - * - HW checksum info (skb->ip_summed) * - HW RX hash (skb_set_hash) * - RX ring dev queue index (skb_record_rx_queue) */
@@ -961,6 +964,31 @@ __bpf_kfunc int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, return -EOPNOTSUPP; } +/** + * bpf_xdp_assert_rx_csum - Assert the packet's L4 checksum is correct. + * @ctx: XDP context pointer. + * + * Mark the frame so that an skb later built out of it (e.g. on the cpumap + * redirect path, see __xdp_build_skb_from_frame()) is set to + * CHECKSUM_UNNECESSARY instead of being validated in software when it enters + * the stack. + * + * This is an assertion made by the XDP program: the kernel cannot verify it. + * The program takes responsibility for the checksum being correct, the same + * way it is already trusted to rewrite arbitrary packet contents. If the + * program modifies L4 data after calling this kfunc the assertion may no + * longer hold. + * + * Return: 0. + */ +__bpf_kfunc int bpf_xdp_assert_rx_csum(struct xdp_md *ctx) +{ + struct xdp_buff *xdp = (struct xdp_buff *)ctx; + + xdp->flags |= XDP_FLAGS_RX_CSUM_UNNECESSARY; + return 0; +} + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(xdp_metadata_kfunc_ids)
@@ -974,6 +1002,18 @@ static const struct btf_kfunc_id_set xdp_metadata_kfunc_set = { .set = &xdp_metadata_kfunc_ids, }; +/* Generic XDP kfuncs that need no driver support and are therefore not + * dev-bound (unlike the rx-metadata kfuncs above). + */ +BTF_KFUNCS_START(xdp_kfunc_ids) +BTF_ID_FLAGS(func, bpf_xdp_assert_rx_csum) +BTF_KFUNCS_END(xdp_kfunc_ids) + +static const struct btf_kfunc_id_set xdp_kfunc_set = { + .owner = THIS_MODULE, + .set = &xdp_kfunc_ids, +}; + BTF_ID_LIST(xdp_metadata_kfunc_ids_unsorted) #define XDP_METADATA_KFUNC(name, _, str, __) BTF_ID(func, str) XDP_METADATA_KFUNC_xxx
@@ -992,7 +1032,13 @@ bool bpf_dev_bound_kfunc_id(u32 btf_id) static int __init xdp_metadata_init(void) { - return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &xdp_metadata_kfunc_set); + int ret; + + ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &xdp_metadata_kfunc_set); + if (ret) + return ret; + + return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &xdp_kfunc_set); } late_initcall(xdp_metadata_init);
--
2.47.0