]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net/ipv6: Introduce payload_len helpers
authorAlice Mikityanska <alice@isovalent.com>
Thu, 5 Feb 2026 13:39:14 +0000 (15:39 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sat, 7 Feb 2026 04:50:03 +0000 (20:50 -0800)
The next commits will transition away from using the hop-by-hop
extension header to encode packet length for BIG TCP. Add wrappers
around ip6->payload_len that return the actual value if it's non-zero,
and calculate it from skb->len if payload_len is set to zero (and a
symmetrical setter).

The new helpers are used wherever the surrounding code supports the
hop-by-hop jumbo header for BIG TCP IPv6, or the corresponding IPv4 code
uses skb_ip_totlen (e.g., in include/net/netfilter/nf_tables_ipv6.h).

No behavioral change in this commit.

Signed-off-by: Alice Mikityanska <alice@isovalent.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260205133925.526371-2-alice.kernel@fastmail.im
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
12 files changed:
include/linux/ipv6.h
include/net/ipv6.h
include/net/netfilter/nf_tables_ipv6.h
net/bridge/br_netfilter_ipv6.c
net/bridge/netfilter/nf_conntrack_bridge.c
net/ipv6/ip6_input.c
net/ipv6/ip6_offload.c
net/ipv6/output_core.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_ovs.c
net/netfilter/nf_log_syslog.c
net/sched/sch_cake.c

index 20aae8357dd151e8c7d6972f41e77cebf1379177..57ab6c97ee7eba3e2b21b04cf6aa9ff9b13f56eb 100644 (file)
@@ -126,6 +126,28 @@ static inline unsigned int ipv6_transport_len(const struct sk_buff *skb)
               skb_network_header_len(skb);
 }
 
+static inline unsigned int
+ipv6_payload_len(const struct sk_buff *skb, const struct ipv6hdr *ip6)
+{
+       u32 len = ntohs(ip6->payload_len);
+
+       return (len || !skb_is_gso(skb) || !skb_is_gso_tcp(skb)) ?
+               len :
+               skb->len - skb_network_offset(skb) - sizeof(struct ipv6hdr);
+}
+
+static inline unsigned int skb_ipv6_payload_len(const struct sk_buff *skb)
+{
+       return ipv6_payload_len(skb, ipv6_hdr(skb));
+}
+
+#define IPV6_MAXPLEN           65535
+
+static inline void ipv6_set_payload_len(struct ipv6hdr *ip6, unsigned int len)
+{
+       ip6->payload_len = len <= IPV6_MAXPLEN ? htons(len) : 0;
+}
+
 /* 
    This structure contains results of exthdrs parsing
    as offsets from skb->nh.
index c27b9d7aeb7cf4611a55abc133d6aaa0d1508a47..1c2d6095b050c4e7bbc5c748c148b1f779b0c2b3 100644 (file)
@@ -25,8 +25,6 @@ struct ip_tunnel_info;
 
 #define SIN6_LEN_RFC2133       24
 
-#define IPV6_MAXPLEN           65535
-
 /*
  *     NextHeader field of IPv6 header
  */
index a0633eeaec977bd014355873fac8c56657c0118a..c53ac00bb974d611cbd0a879f669c9ebd5eff36f 100644 (file)
@@ -42,7 +42,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
        if (ip6h->version != 6)
                return -1;
 
-       pkt_len = ntohs(ip6h->payload_len);
+       pkt_len = ipv6_payload_len(pkt->skb, ip6h);
        skb_len = pkt->skb->len - skb_network_offset(pkt->skb);
        if (pkt_len + sizeof(*ip6h) > skb_len)
                return -1;
@@ -86,7 +86,7 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt)
        if (ip6h->version != 6)
                goto inhdr_error;
 
-       pkt_len = ntohs(ip6h->payload_len);
+       pkt_len = ipv6_payload_len(pkt->skb, ip6h);
        if (pkt_len + sizeof(*ip6h) > pkt->skb->len) {
                idev = __in6_dev_get(nft_in(pkt));
                __IP6_INC_STATS(nft_net(pkt), idev, IPSTATS_MIB_INTRUNCATEDPKTS);
index e0421eaa3abc78b8587d551c6e91682bba28c79d..76ce70b4e7f3b8643dc17c8a8ba08e6d654ed56d 100644 (file)
@@ -58,7 +58,7 @@ int br_validate_ipv6(struct net *net, struct sk_buff *skb)
        if (hdr->version != 6)
                goto inhdr_error;
 
-       pkt_len = ntohs(hdr->payload_len);
+       pkt_len = ipv6_payload_len(skb, hdr);
        if (hdr->nexthdr == NEXTHDR_HOP && nf_ip6_check_hbh_len(skb, &pkt_len))
                goto drop;
 
index 3b28b84191bebd7dd971a1e685dfa5c659f61782..58a33d0380b00b12027a12f02af3391ea238181c 100644 (file)
@@ -229,7 +229,7 @@ static int nf_ct_br_ipv6_check(const struct sk_buff *skb)
        if (hdr->version != 6)
                return -1;
 
-       len = ntohs(hdr->payload_len) + sizeof(struct ipv6hdr) + nhoff;
+       len = ipv6_payload_len(skb, hdr) + sizeof(struct ipv6hdr) + nhoff;
        if (skb->len < len)
                return -1;
 
@@ -269,7 +269,7 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
                if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
                        return NF_ACCEPT;
 
-               len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
+               len = sizeof(struct ipv6hdr) + skb_ipv6_payload_len(skb);
                if (pskb_trim_rcsum(skb, len))
                        return NF_ACCEPT;
 
index 168ec07e31cc378843703483ae43bf30260f027b..2bcb981c91aa83fe08d782c29a185c8559aeacde 100644 (file)
@@ -262,7 +262,7 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
        skb->transport_header = skb->network_header + sizeof(*hdr);
        IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
-       pkt_len = ntohs(hdr->payload_len);
+       pkt_len = ipv6_payload_len(skb, hdr);
 
        /* pkt_len may be zero if Jumbo payload option is present */
        if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
index 32a104ead8760d33e152e0b0a6a6896d70d155b5..ceb4752a535871435803e3e8ffd6597580d3ec92 100644 (file)
@@ -366,12 +366,11 @@ INDIRECT_CALLABLE_SCOPE int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
                hop_jumbo->jumbo_payload_len = htonl(payload_len + hoplen);
 
                iph->nexthdr = NEXTHDR_HOP;
-               iph->payload_len = 0;
-       } else {
-               iph = (struct ipv6hdr *)(skb->data + nhoff);
-               iph->payload_len = htons(payload_len);
        }
 
+       iph = (struct ipv6hdr *)(skb->data + nhoff);
+       ipv6_set_payload_len(iph, payload_len);
+
        nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &ops);
 
        if (likely(ops == &net_hotdata.tcpv6_offload))
index 1c9b283a4132dc4b3a8241b9e9255b407e03fe49..cba1684a3f30ff98517d873ddb8e97f32adc9791 100644 (file)
@@ -125,12 +125,7 @@ EXPORT_SYMBOL(ip6_dst_hoplimit);
 
 int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
-       int len;
-
-       len = skb->len - sizeof(struct ipv6hdr);
-       if (len > IPV6_MAXPLEN)
-               len = 0;
-       ipv6_hdr(skb)->payload_len = htons(len);
+       ipv6_set_payload_len(ipv6_hdr(skb), skb->len - sizeof(struct ipv6hdr));
        IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
        /* if egress device is enslaved to an L3 master device pass the
index 64c697212578ae3b5c31420c79a22e12de34334e..f861d116cc33feecfaf00aa9b7a4f2f921f8ce83 100644 (file)
@@ -949,7 +949,7 @@ ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af,
                *next_protocol = IPPROTO_IPV6;
                if (payload_len)
                        *payload_len =
-                               ntohs(old_ipv6h->payload_len) +
+                               ipv6_payload_len(skb, old_ipv6h) +
                                sizeof(*old_ipv6h);
                old_dsfield = ipv6_get_dsfield(old_ipv6h);
                *ttl = old_ipv6h->hop_limit;
index 068e9489e1c27684788668dc4c873b8c82476ad8..a6988eeb15797367a90500a0add24b1c542852be 100644 (file)
@@ -121,7 +121,7 @@ int nf_ct_skb_network_trim(struct sk_buff *skb, int family)
                len = skb_ip_totlen(skb);
                break;
        case NFPROTO_IPV6:
-               len = ntohs(ipv6_hdr(skb)->payload_len);
+               len = skb_ipv6_payload_len(skb);
                if (ipv6_hdr(skb)->nexthdr == NEXTHDR_HOP) {
                        int err = nf_ip6_check_hbh_len(skb, &len);
 
index 86d5fc5d28e3b6a9c2bc49374ff756aad5beffd1..41503847d9d7fb21824fabb1b57b45f2622b9310 100644 (file)
@@ -561,7 +561,7 @@ dump_ipv6_packet(struct net *net, struct nf_log_buf *m,
 
        /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
        nf_log_buf_add(m, "LEN=%zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
-                      ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
+                      ipv6_payload_len(skb, ih) + sizeof(struct ipv6hdr),
                       (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
                       ih->hop_limit,
                       (ntohl(*(__be32 *)ih) & 0x000fffff));
index fd56b7d883014e834f22a0a7b981bcd48e6a4227..d2bbd5654d5b3ae5553a79f8da047d5f7fa07620 100644 (file)
@@ -1279,7 +1279,7 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
                            ipv6_addr_cmp(&ipv6h_check->daddr, &ipv6h->daddr))
                                continue;
 
-                       seglen = ntohs(ipv6h_check->payload_len);
+                       seglen = ipv6_payload_len(skb, ipv6h_check);
                } else {
                        WARN_ON(1);  /* shouldn't happen */
                        continue;