Commit 21f4d45e authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Jakub Kicinski
Browse files

net/ip6_tunnel: Prevent perpetual tunnel growth



Similarly to ipv4 tunnel, ipv6 version updates dev->needed_headroom, too.
While ipv4 tunnel headroom adjustment growth was limited in
commit 5ae1e992 ("net: ip_tunnel: prevent perpetual headroom growth"),
ipv6 tunnel yet increases the headroom without any ceiling.

Reflect ipv4 tunnel headroom adjustment limit on ipv6 version.

Credits to Francesco Ruggeri, who was originally debugging this issue
and wrote local Arista-specific patch and a reproducer.

Fixes: 8eb30be0 ("ipv6: Create ip6_tnl_xmit")
Cc: Florian Westphal <fw@strlen.de>
Cc: Francesco Ruggeri <fruggeri05@gmail.com>
Signed-off-by: default avatarDmitry Safonov <dima@arista.com>
Link: https://patch.msgid.link/20251009-ip6_tunnel-headroom-v2-1-8e4dbd8f7e35@arista.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e4d0c909
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -611,6 +611,21 @@ struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md,
int skb_tunnel_check_pmtu(struct sk_buff *skb, struct dst_entry *encap_dst,
			  int headroom, bool reply);

static inline void ip_tunnel_adj_headroom(struct net_device *dev,
					  unsigned int headroom)
{
	/* we must cap headroom to some upperlimit, else pskb_expand_head
	 * will overflow header offsets in skb_headers_offset_update().
	 */
	const unsigned int max_allowed = 512;

	if (headroom > max_allowed)
		headroom = max_allowed;

	if (headroom > READ_ONCE(dev->needed_headroom))
		WRITE_ONCE(dev->needed_headroom, headroom);
}

int iptunnel_handle_offloads(struct sk_buff *skb, int gso_type_mask);

static inline int iptunnel_pull_offloads(struct sk_buff *skb)
+0 −14
Original line number Diff line number Diff line
@@ -568,20 +568,6 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
	return 0;
}

static void ip_tunnel_adj_headroom(struct net_device *dev, unsigned int headroom)
{
	/* we must cap headroom to some upperlimit, else pskb_expand_head
	 * will overflow header offsets in skb_headers_offset_update().
	 */
	static const unsigned int max_allowed = 512;

	if (headroom > max_allowed)
		headroom = max_allowed;

	if (headroom > READ_ONCE(dev->needed_headroom))
		WRITE_ONCE(dev->needed_headroom, headroom);
}

void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
		       u8 proto, int tunnel_hlen)
{
+1 −2
Original line number Diff line number Diff line
@@ -1257,8 +1257,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
	 */
	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr)
			+ dst->header_len + t->hlen;
	if (max_headroom > READ_ONCE(dev->needed_headroom))
		WRITE_ONCE(dev->needed_headroom, max_headroom);
	ip_tunnel_adj_headroom(dev, max_headroom);

	err = ip6_tnl_encap(skb, t, &proto, fl6);
	if (err)