Commit 1f7ec1b3 authored by Yan Zhai's avatar Yan Zhai Committed by Jakub Kicinski
Browse files

ipv6: refactor ip6_finish_output for GSO handling



Separate GSO and non-GSO packets handling to make the logic cleaner. For
GSO packets, frag_max_size check can be omitted because it is only
useful for packets defragmented by netfilter hooks. Both local output
and GRO logic won't produce GSO packets when defragment is needed. This
also mirrors what IPv4 side code is doing.

Suggested-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarYan Zhai <yan@cloudflare.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/0e1d4599f858e2becff5c4fe0b5f843236bc3fe8.1698156966.git.yan@cloudflare.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e57a3447
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -172,6 +172,16 @@ ip6_finish_output_gso_slowpath_drop(struct net *net, struct sock *sk,
	return ret;
}

static int ip6_finish_output_gso(struct net *net, struct sock *sk,
				 struct sk_buff *skb, unsigned int mtu)
{
	if (!(IP6CB(skb)->flags & IP6SKB_FAKEJUMBO) &&
	    !skb_gso_validate_network_len(skb, mtu))
		return ip6_finish_output_gso_slowpath_drop(net, sk, skb, mtu);

	return ip6_finish_output2(net, sk, skb);
}

static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	unsigned int mtu;
@@ -185,15 +195,13 @@ static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff
#endif

	mtu = ip6_skb_dst_mtu(skb);
	if (skb_is_gso(skb) &&
	    !(IP6CB(skb)->flags & IP6SKB_FAKEJUMBO) &&
	    !skb_gso_validate_network_len(skb, mtu))
		return ip6_finish_output_gso_slowpath_drop(net, sk, skb, mtu);
	if (skb_is_gso(skb))
		return ip6_finish_output_gso(net, sk, skb, mtu);

	if ((skb->len > mtu && !skb_is_gso(skb)) ||
	if (skb->len > mtu ||
	    (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size))
		return ip6_fragment(net, sk, skb, ip6_finish_output2);
	else

	return ip6_finish_output2(net, sk, skb);
}