Thread (19 messages) 19 messages, 2 authors, 13d ago

[PATCH net-next v4 04/10] ip_tunnel: add __iptunnel_pull_header_reason()

flat view
COOLING13d

From: Anton Danilov <hidden>
Date: 2026-09-22 22:15:28
Also in: lkml
Subsystem: networking [general], networking [ipv4/ipv6], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds

Revision v4 of 5 in this series.

Revisions (5)
  1. v1 [diff vs current]
  2. v2 [diff vs current]
  3. v3 [diff vs current]
  4. v4 current
  5. v5 [diff vs current]
__iptunnel_pull_header() returns -ENOMEM whenever it fails. It can
fail in two pskb_may_pull() calls, one for the tunnel header and one
for the inner Ethernet header of ETH_P_TEB, and in the skb_unclone()
done for GSO packets. pskb_may_pull() fails when the packet is shorter
than the requested length as well as when pulling from the frags cannot
allocate, so a truncated packet and an allocation failure look the same
to the callers. The ones that report a drop reason can only pick
SKB_DROP_REASON_NOMEM, as vxlan_rcv() does, and so would the GRE
receive paths converted by the following patches. In ip6_gre,
gre_rcv() calls the helper before the tunnel lookup, so a packet from
any sender whose ETH_P_TEB inner Ethernet header or WCCPv2 extra word
is cut short would be reported as an out of memory condition.

Add __iptunnel_pull_header_reason(), which returns the reason
pskb_may_pull_reason() already computes, SKB_DROP_REASON_NOMEM when
skb_unclone() fails, and SKB_NOT_DROPPED_YET on success. Turn
__iptunnel_pull_header() into a static inline wrapper that keeps
returning -ENOMEM on any failure, so its existing callers are left
unchanged; the export moves to the new function.

Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Anton Danilov <redacted>
---
 include/net/ip_tunnels.h  | 13 +++++++++++--
 net/ipv4/ip_tunnel_core.c | 24 ++++++++++++++++--------
 2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 7102aa11fae2..c68031d01c39 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -614,8 +614,17 @@ static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
 	return INET_ECN_encapsulate(tos, inner);
 }
 
-int __iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
-			   __be16 inner_proto, bool raw_proto, bool xnet);
+enum skb_drop_reason
+__iptunnel_pull_header_reason(struct sk_buff *skb, int hdr_len,
+			      __be16 inner_proto, bool raw_proto, bool xnet);
+
+static inline int __iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
+					 __be16 inner_proto, bool raw_proto,
+					 bool xnet)
+{
+	return __iptunnel_pull_header_reason(skb, hdr_len, inner_proto,
+					     raw_proto, xnet) ? -ENOMEM : 0;
+}
 
 static inline int iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
 				       __be16 inner_proto, bool xnet)
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index bab42b9e277f..51f1537ce6c1 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -106,19 +106,24 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(iptunnel_xmit);
 
-int __iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
-			   __be16 inner_proto, bool raw_proto, bool xnet)
+enum skb_drop_reason
+__iptunnel_pull_header_reason(struct sk_buff *skb, int hdr_len,
+			      __be16 inner_proto, bool raw_proto, bool xnet)
 {
-	if (unlikely(!pskb_may_pull(skb, hdr_len)))
-		return -ENOMEM;
+	enum skb_drop_reason reason;
+
+	reason = pskb_may_pull_reason(skb, hdr_len);
+	if (unlikely(reason))
+		return reason;
 
 	skb_pull_rcsum(skb, hdr_len);
 
 	if (!raw_proto && inner_proto == htons(ETH_P_TEB)) {
 		struct ethhdr *eh;
 
-		if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
-			return -ENOMEM;
+		reason = pskb_may_pull_reason(skb, ETH_HLEN);
+		if (unlikely(reason))
+			return reason;
 
 		eh = (struct ethhdr *)skb->data;
 		if (likely(eth_proto_is_802_3(eh->h_proto)))
@@ -135,9 +140,12 @@ int __iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
 	skb_set_queue_mapping(skb, 0);
 	skb_scrub_packet(skb, xnet);
 
-	return iptunnel_pull_offloads(skb);
+	if (unlikely(iptunnel_pull_offloads(skb)))
+		return SKB_DROP_REASON_NOMEM;
+
+	return SKB_NOT_DROPPED_YET;
 }
-EXPORT_SYMBOL_GPL(__iptunnel_pull_header);
+EXPORT_SYMBOL_GPL(__iptunnel_pull_header_reason);
 
 struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md,
 					     gfp_t flags)
-- 
2.47.3
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help