Implement functionality that enables drivers to expose to XDP code checksum information that consists of: - Checksum status - bitfield that consists of - number of consecutive validated checksums. This is almost the same as csum_level in skb, but starts with 1. Enum names for those bits still use checksum level concept, so it is less confusing for driver developers. - Is checksum partial? This bit cannot coexist with any other - Is there a complete checksum available? - Additional checksum data, a union of: - checksum start and offset, if checksum is partial - complete checksum, if available Signed-off-by: Larysa Zaremba <larysa.zaremba@xxxxxxxxx> --- Documentation/networking/xdp-rx-metadata.rst | 3 ++ include/linux/netdevice.h | 3 ++ include/net/xdp.h | 46 ++++++++++++++++++++ kernel/bpf/offload.c | 2 + net/core/xdp.c | 23 ++++++++++ 5 files changed, 77 insertions(+) diff --git a/Documentation/networking/xdp-rx-metadata.rst b/Documentation/networking/xdp-rx-metadata.rst index ea6dd79a21d3..7f056a44f682 100644 --- a/Documentation/networking/xdp-rx-metadata.rst +++ b/Documentation/networking/xdp-rx-metadata.rst @@ -26,6 +26,9 @@ metadata is supported, this set will grow: .. kernel-doc:: net/core/xdp.c :identifiers: bpf_xdp_metadata_rx_vlan_tag +.. kernel-doc:: net/core/xdp.c + :identifiers: bpf_xdp_metadata_rx_csum + An XDP program can use these kfuncs to read the metadata into stack variables for its own consumption. Or, to pass the metadata on to other consumers, an XDP program can store it into the metadata area carried diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 028dcc4fd02d..a950cec76945 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1660,6 +1660,9 @@ struct xdp_metadata_ops { enum xdp_rss_hash_type *rss_type); int (*xmo_rx_vlan_tag)(const struct xdp_md *ctx, u16 *vlan_tci, __be16 *vlan_proto); + int (*xmo_rx_csum)(const struct xdp_md *ctx, + enum xdp_csum_status *csum_status, + union xdp_csum_info *csum_info); }; /** diff --git a/include/net/xdp.h b/include/net/xdp.h index 89c58f56ffc6..7e6163e5002a 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -391,6 +391,8 @@ void xdp_attachment_setup(struct xdp_attachment_info *info, bpf_xdp_metadata_rx_hash) \ XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_VLAN_TAG, \ bpf_xdp_metadata_rx_vlan_tag) \ + XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_CSUM, \ + bpf_xdp_metadata_rx_csum) \ enum { #define XDP_METADATA_KFUNC(name, _) name, @@ -448,6 +450,50 @@ enum xdp_rss_hash_type { XDP_RSS_TYPE_L4_IPV6_SCTP_EX = XDP_RSS_TYPE_L4_IPV6_SCTP | XDP_RSS_L3_DYNHDR, }; +union xdp_csum_info { + /* Checksum referred to by ``csum_start + csum_offset`` is considered + * valid, but was never calculated, TX device has to do this, + * starting from csum_start packet byte. + * Any preceding checksums are also considered valid. + * Available, if ``status == XDP_CHECKSUM_PARTIAL``. + */ + struct { + u16 csum_start; + u16 csum_offset; + }; + + /* Checksum, calculated over the whole packet. + * Available, if ``status & XDP_CHECKSUM_COMPLETE``. + */ + u32 checksum; +}; + +enum xdp_csum_status { + /* HW had parsed several transport headers and validated their + * checksums, same as ``CHECKSUM_UNNECESSARY`` in ``sk_buff``. + * 3 least significant bytes contain number of consecutive checksums, + * starting with the outermost, reported by hardware as valid. + * ``sk_buff`` checksum level (``csum_level``) notation is provided + * for driver developers. + */ + XDP_CHECKSUM_VALID_LVL0 = 1, /* 1 outermost checksum */ + XDP_CHECKSUM_VALID_LVL1 = 2, /* 2 outermost checksums */ + XDP_CHECKSUM_VALID_LVL2 = 3, /* 3 outermost checksums */ + XDP_CHECKSUM_VALID_LVL3 = 4, /* 4 outermost checksums */ + XDP_CHECKSUM_VALID_NUM_MASK = GENMASK(2, 0), + XDP_CHECKSUM_VALID = XDP_CHECKSUM_VALID_NUM_MASK, + + /* Occurs if packet is sent virtually (between Linux VMs / containers) + * This status cannot coexist with any other. + * Refer to ``csum_start`` and ``csum_offset`` in ``xdp_csum_info`` + * for more information. + */ + XDP_CHECKSUM_PARTIAL = BIT(3), + + /* Checksum, calculated over the entire packet is provided */ + XDP_CHECKSUM_COMPLETE = BIT(4), +}; + #ifdef CONFIG_NET u32 bpf_xdp_metadata_kfunc_id(int id); bool bpf_dev_bound_kfunc_id(u32 btf_id); diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c index 986e7becfd42..f60a6add5273 100644 --- a/kernel/bpf/offload.c +++ b/kernel/bpf/offload.c @@ -850,6 +850,8 @@ void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog, u32 func_id) p = ops->xmo_rx_hash; else if (func_id == bpf_xdp_metadata_kfunc_id(XDP_METADATA_KFUNC_RX_VLAN_TAG)) p = ops->xmo_rx_vlan_tag; + else if (func_id == bpf_xdp_metadata_kfunc_id(XDP_METADATA_KFUNC_RX_CSUM)) + p = ops->xmo_rx_csum; out: up_read(&bpf_devs_lock); diff --git a/net/core/xdp.c b/net/core/xdp.c index 8b55419d332e..d4ea54046afc 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -772,6 +772,29 @@ __bpf_kfunc int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, return -EOPNOTSUPP; } +/** + * bpf_xdp_metadata_rx_csum - Get checksum status with additional info. + * @ctx: XDP context pointer. + * @csum_status: Destination for checksum status. + * @csum_info: Destination for complete checksum or partial checksum offset. + * + * Status (@csum_status) is a bitfield that informs, what checksum + * processing was performed. Additional results of such processing, + * such as complete checksum or partial checksum offsets, + * are passed as info (@csum_info). + * + * Return: + * * Returns 0 on success or ``-errno`` on error. + * * ``-EOPNOTSUPP`` : device driver doesn't implement kfunc + * * ``-ENODATA`` : Checksum status is unknown + */ +__bpf_kfunc int bpf_xdp_metadata_rx_csum(const struct xdp_md *ctx, + enum xdp_csum_status *csum_status, + union xdp_csum_info *csum_info) +{ + return -EOPNOTSUPP; +} + __diag_pop(); BTF_SET8_START(xdp_metadata_kfunc_ids) -- 2.41.0