Add a new BPF kfunc, bpf_skb_rx_checksum(), that allows TC and other
skb-attached BPF programs to read the skb->ip_summed field and
associated checksum metadata. This is needed because the existing
bpf_csum_level() helper only distinguishes CHECKSUM_UNNECESSARY
from all other states, making it unsuitable when the caller needs
to differentiate CHECKSUM_NONE from CHECKSUM_COMPLETE (e.g. after
XDP_PASS where the driver may have set either).

The kfunc writes two output values:
  - ip_summed: the raw skb->ip_summed value
               (CHECKSUM_NONE=0, CHECKSUM_UNNECESSARY=1,
                CHECKSUM_COMPLETE=2, CHECKSUM_PARTIAL=3)
  - csum_meta: CHECKSUM_COMPLETE -> hardware checksum (skb->csum)
               CHECKSUM_UNNECESSARY -> checksum level (skb->csum_level)
               otherwise -> 0

Signed-off-by: Lorenzo Bianconi <[email protected]>
---
 net/core/filter.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/net/core/filter.c b/net/core/filter.c
index b446aa8be5c3..71d58ea53512 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -12546,6 +12546,36 @@ __bpf_kfunc int bpf_xdp_pull_data(struct xdp_md *x, 
u32 len)
        return 0;
 }
 
+/**
+ * bpf_skb_rx_checksum() - Read skb RX checksum info.
+ * @skb_: socket buffer to read from
+ * @ip_summed: return value for skb->ip_summed
+ * @csum_meta: checksum metadata
+ *
+ * Reads the checksum-related fields from a socket buffer. For
+ * %CHECKSUM_COMPLETE, csum_meta reports the hardware checksum value.
+ * For %CHECKSUM_UNNECESSARY, csum_meta reports the checksum level.
+ * For %CHECKSUM_NONE, csum_meta is zero.
+ *
+ * Return:
+ * * %0 - success
+ */
+__bpf_kfunc int bpf_skb_rx_checksum(struct __sk_buff *skb_, u32 *ip_summed,
+                                   u32 *csum_meta)
+{
+       struct sk_buff *skb = (struct sk_buff *)skb_;
+
+       *ip_summed = skb->ip_summed;
+       if (skb->ip_summed == CHECKSUM_COMPLETE)
+               *csum_meta = skb->csum;
+       else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+               *csum_meta = skb->csum_level;
+       else
+               *csum_meta = 0;
+
+       return 0;
+}
+
 __bpf_kfunc_end_defs();
 
 int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags,
@@ -12565,6 +12595,7 @@ int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, 
u64 flags,
 
 BTF_KFUNCS_START(bpf_kfunc_check_set_skb)
 BTF_ID_FLAGS(func, bpf_dynptr_from_skb)
+BTF_ID_FLAGS(func, bpf_skb_rx_checksum)
 BTF_KFUNCS_END(bpf_kfunc_check_set_skb)
 
 BTF_KFUNCS_START(bpf_kfunc_check_set_skb_meta)

-- 
2.55.0


Reply via email to