cpumap, veth and BPF_PROG_RUN build the skb from an xdp_frame with __xdp_build_skb_from_frame(). It now calls the new helper xdp_skb_ext_to_skb() if the xdp_frame has the XDP_FLAGS_HAS_SKB_EXT flag. Three drivers (atlantic, mana and netvsc) call the wrapper xdp_build_skb_from_frame() in their RX and TX routines, and then set the skb fields from the RX descriptor or transmit the skb. The stored values must be ignored there to keep their behaviour consistent. So the wrapper clears the flag. A driver that supports them calls xdp_skb_ext_to_skb() itself, as ice does in a later patch. xdp_skb_ext_to_skb() is based on [1]. Link: https://lore.kernel.org/all/175146831960.1421237.9105904582430357235.stgit@firesoul/ [1] Signed-off-by: Tianyi Gao --- include/net/xdp.h | 7 ++++++ net/core/xdp.c | 54 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/include/net/xdp.h b/include/net/xdp.h index d8b77d80bfbe..7c9a812b6e86 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -329,6 +329,11 @@ static __always_inline bool xdp_frame_has_frags(const struct xdp_frame *frame) return !!(frame->flags & XDP_FLAGS_HAS_FRAGS); } +static __always_inline bool xdp_frame_has_skb_ext(const struct xdp_frame *frame) +{ + return !!(frame->flags & XDP_FLAGS_HAS_SKB_EXT); +} + static __always_inline u32 xdp_frame_get_skb_flags(const struct xdp_frame *frame) { @@ -503,6 +508,8 @@ static __always_inline void *xdp_skb_ext_end(const struct xdp_buff *xdp) return (void *)ext + ext->chunks * XDP_SKB_EXT_ALIGN; } +void xdp_skb_ext_to_skb(struct sk_buff *skb, const struct xdp_skb_ext *ext); + void __xdp_return(netmem_ref netmem, enum xdp_mem_type mem_type, bool napi_direct, struct xdp_buff *xdp); void xdp_return_frame(struct xdp_frame *xdpf); diff --git a/net/core/xdp.c b/net/core/xdp.c index eea04e7b7204..9f311b3c0d2b 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -829,10 +829,10 @@ 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); + if (xdp_frame_has_skb_ext(xdpf)) + xdp_skb_ext_to_skb(skb, xdp_skb_ext(xdpf)); /* 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) */ @@ -857,6 +857,9 @@ struct sk_buff *xdp_build_skb_from_frame(struct xdp_frame *xdpf, memset(skb, 0, offsetof(struct sk_buff, tail)); + /* The callers set the RX fields themselves or transmit the skb */ + xdpf->flags &= ~XDP_FLAGS_HAS_SKB_EXT; + return __xdp_build_skb_from_frame(xdpf, skb, dev); } EXPORT_SYMBOL_GPL(xdp_build_skb_from_frame); @@ -1065,6 +1068,53 @@ static void *xdp_skb_ext_add(struct xdp_buff *xdp, enum xdp_skb_ext_id id) return (void *)ext + newoff * XDP_SKB_EXT_ALIGN; } +static const void *xdp_skb_ext_get(const struct xdp_skb_ext *ext, + enum xdp_skb_ext_id id) +{ + u8 off = ext->offset[id]; + + if (!(off & XDP_SKB_EXT_ENTRY_ACTIVE)) + return NULL; + off &= ~XDP_SKB_EXT_ENTRY_ACTIVE; + + return (const void *)ext + off * XDP_SKB_EXT_ALIGN; +} + +/** + * xdp_skb_ext_to_skb - Set the stored RX metadata on an skb. + * @skb: The skb that is built from the packet. + * @ext: The skb core extension area of the packet. + * + * Call it only when the packet has the XDP_FLAGS_HAS_SKB_EXT flag. + */ +void xdp_skb_ext_to_skb(struct sk_buff *skb, const struct xdp_skb_ext *ext) +{ + const struct xdp_skb_ext_hash *hash; + const struct xdp_skb_ext_vlan *vlan; + const struct xdp_skb_ext_csum *csum; + + hash = xdp_skb_ext_get(ext, XDP_SKB_EXT_HASH); + if (hash) { + enum pkt_hash_types type = PKT_HASH_TYPE_NONE; + + if (hash->type & XDP_RSS_L4) + type = PKT_HASH_TYPE_L4; + else if (hash->type & (XDP_RSS_L3_IPV4 | XDP_RSS_L3_IPV6)) + type = PKT_HASH_TYPE_L3; + skb_set_hash(skb, hash->val, type); + } + + vlan = xdp_skb_ext_get(ext, XDP_SKB_EXT_VLAN); + if (vlan) + __vlan_hwaccel_put_tag(skb, vlan->proto, vlan->tci); + + csum = xdp_skb_ext_get(ext, XDP_SKB_EXT_CSUM); + if (csum) { + skb->ip_summed = csum->ip_summed; + skb->csum_level = csum->level; + } +} + __bpf_kfunc_start_defs(); /** -- 2.56.0