bpf_xdp_skb_ext_del() deletes the stored entry for an id. A program on cpumap or veth can use it to drop RX metadata that an earlier program stored. Without the XDP_FLAGS_HAS_SKB_EXT flag, the kfunc does nothing, because the header bytes may then belong to the packet. The kfunc only clears XDP_SKB_EXT_ENTRY_ACTIVE, so a later store of the same id reuses its offset. The flag and the size of the area stay the same, also after the last delete. To give the bytes back, the kfunc would have to move the entries after the deleted one. The cost is headroom that bpf_xdp_adjust_head() and bpf_xdp_adjust_meta() cannot use. Signed-off-by: Tianyi Gao --- __skb_ext_del() frees struct skb_ext after the last delete, because it comes from a slab cache. The skb core extension area uses existing headroom, so it is not freed. --- include/net/xdp.h | 8 ++++++++ net/core/xdp.c | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/net/xdp.h b/include/net/xdp.h index c888353425d4..23c976e92898 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -486,6 +486,14 @@ static __always_inline struct xdp_skb_ext *xdp_skb_ext(struct xdp_frame *frame) return (void *)(frame + 1); } +static __always_inline struct xdp_skb_ext * +xdp_buff_skb_ext(const struct xdp_buff *xdp) +{ + if (!xdp_buff_has_skb_ext(xdp)) + return NULL; + return xdp_skb_ext(xdp->data_hard_start); +} + static __always_inline void *xdp_skb_ext_end(const struct xdp_buff *xdp) { struct xdp_skb_ext *ext = xdp_skb_ext(xdp->data_hard_start); diff --git a/net/core/xdp.c b/net/core/xdp.c index 97dc0e403a78..2c1d5ec3311b 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -991,6 +991,7 @@ bool bpf_dev_bound_kfunc_id(u32 btf_id) } #define XDP_SKB_EXT_CHUNKSIZEOF(x) DIV_ROUND_UP(sizeof(x), XDP_SKB_EXT_ALIGN) +/* A deleted entry keeps its offset, without this bit */ #define XDP_SKB_EXT_ENTRY_ACTIVE BIT(7) struct xdp_skb_ext_hash { @@ -1119,11 +1120,36 @@ __bpf_kfunc int bpf_xdp_skb_ext_store_rx_vlan(struct xdp_md *ctx, return 0; } +/** + * bpf_xdp_skb_ext_del - Delete a stored entry of this packet. + * @ctx: XDP context pointer. + * @id: Entry id, see &enum xdp_skb_ext_id. + * + * Return: + * * Returns 0 on success, also when the entry is not stored. + * * ``-EINVAL`` : @id is not a valid entry id + */ +__bpf_kfunc int bpf_xdp_skb_ext_del(struct xdp_md *ctx, enum xdp_skb_ext_id id) +{ + struct xdp_buff *xdp = (struct xdp_buff *)ctx; + struct xdp_skb_ext *ext; + + if ((u32)id >= XDP_SKB_EXT_NUM) + return -EINVAL; + + ext = xdp_buff_skb_ext(xdp); + if (ext) + ext->offset[id] &= ~XDP_SKB_EXT_ENTRY_ACTIVE; + + return 0; +} + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(xdp_skb_ext_kfunc_ids) BTF_ID_FLAGS(func, bpf_xdp_skb_ext_store_rx_hash) BTF_ID_FLAGS(func, bpf_xdp_skb_ext_store_rx_vlan) +BTF_ID_FLAGS(func, bpf_xdp_skb_ext_del) BTF_KFUNCS_END(xdp_skb_ext_kfunc_ids) static const struct btf_kfunc_id_set xdp_skb_ext_kfunc_set = { -- 2.56.0