FAILED: patch "[PATCH] tcp: clamp route advmss to TCP_MIN_MSS" failed to apply to 6.18-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x 870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026083104-huddle-balancing-d57b@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1 Mon Sep 17 00:00:00 2001
From: Yong Wang <[email protected]>
Date: Wed, 19 Aug 2026 23:22:04 +0800
Subject: [PATCH] tcp: clamp route advmss to TCP_MIN_MSS
tcp_select_initial_window() assumes that callers never pass an MSS smaller than 1, but route-derived advmss values can violate that assumption.
A too-small explicit RTAX_ADVMSS is one way to get there, but it is not the only one. The same divide-by-zero can also be reached through the "default advmss" path when RTAX_ADVMSS is left at 0 and the effective advmss is later driven down by route MTU and min_adv_mss.
Introduce a tcp_dst_advmss() helper that clamps route advmss to TCP_MIN_MSS before TCP consumes it, and use it in the TCP paths that derive advmss from dst metrics. This keeps the effective MSS from dropping to zero before tcp_select_initial_window() rounds the receive window.
include/net/tcp.h +5 -0
@@ -1782,6 +1782,11 @@ static inline int tcp_full_space(const struct sock *sk)return tcp_win_from_space (sk,READ_ONCE (sk->sk_rcvbuf)); } +static inline u32 tcp_dst_advmss (const struct dst_entry *dst) +{ +return max_t (u32,dst_metric_advmss (dst),TCP_MIN_MSS ); +} +static inline void __tcp_adjust_rcv_ssthresh (struct sock *sk,u32 new_ssthresh) {int unused_mem =sk_unused_reserved_mem (sk);
net/ipv4/tcp_ipv4.c +1 -1
@@ -1736,7 +1736,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst4_mtu (dst)); - newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst)); + newtp->advmss =tcp_mss_clamp (tcp_sk (sk),tcp_dst_advmss (dst));tcp_initialize_rcv_mss (newsk);
net/ipv4/tcp_minisocks.c +1 -1
@@ -440,7 +440,7 @@ void tcp_openreq_init_rwin(struct request_sock *req,u32 rcv_wnd;int mss; - mss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + mss =tcp_mss_clamp (tp,tcp_dst_advmss (dst)); window_clamp =READ_ONCE (tp->window_clamp);/* Set this up on the first call only */ req->rsk_window_clamp = window_clamp ? :dst_metric (dst,RTAX_WINDOW );
net/ipv4/tcp_output.c +3 -3
@@ -143,7 +143,7 @@ static __u16 tcp_advertise_mss(struct sock *sk)int mss = tp->advmss;if (dst) { -unsigned int metric =dst_metric_advmss (dst); +unsigned int metric =tcp_dst_advmss (dst);if (metric < mss) { mss = metric;
@@ -3972,7 +3972,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, }skb_dst_set (skb, dst); - mss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + mss =tcp_mss_clamp (tp,tcp_dst_advmss (dst));memset (&opts,0 ,sizeof (opts)); now =tcp_clock_ns ();
@@ -4128,7 +4128,7 @@ static void tcp_connect_init(struct sock *sk)if (!tp->window_clamp)WRITE_ONCE (tp->window_clamp,dst_metric (dst,RTAX_WINDOW )); - tp->advmss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + tp->advmss =tcp_mss_clamp (tp,tcp_dst_advmss (dst));tcp_initialize_rcv_mss (sk);
net/ipv6/tcp_ipv6.c +1 -1
@@ -1487,7 +1487,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst6_mtu (dst)); - newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst)); + newtp->advmss =tcp_mss_clamp (tcp_sk (sk),tcp_dst_advmss (dst));tcp_initialize_rcv_mss (newsk);
Sasha Levin
maintainerPATCH 1/6 ipv6: pass proto by value to ipv6_push_nfrag_opts() and ipv6_push_frag_opts()
From: Eric Dumazet <[email protected]>
[ Upstream commit 1bc46dd209667346c5aa56c351995e7c260696d0 ]
With CONFIG_STACKPROTECTOR_STRONG=y, it is better to avoid passing a pointer to an automatic variable.
Change these exported functions to return 'u8 proto' instead of void.
- ipv6_push_nfrag_opts()
- ipv6_push_frag_opts()
For instance, replace
ipv6_push_frag_opts(skb, opt, &proto); with: proto = ipv6_push_frag_opts(skb, opt, proto);
Note that even after this change, ip6_xmit() has to use a stack canary because of @first_hop variable.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- include/net/ipv6.h | 10 ++++---- net/ipv6/exthdrs.c | 55 +++++++++++++++++++++++-------------------- net/ipv6/ip6_output.c | 19 ++++++++------- net/ipv6/ip6_tunnel.c | 2 +- 4 files changed, 46 insertions(+), 40 deletions(-)
include/net/ipv6.h +5 -5
@@ -1147,11 +1147,11 @@ int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);* Extension header (options) processing */ -void ipv6_push_nfrag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, -u8 *proto,struct in6_addr **daddr_p, -struct in6_addr *saddr); -void ipv6_push_frag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, -u8 *proto); +u8 ipv6_push_nfrag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, +u8 proto,struct in6_addr **daddr_p, +struct in6_addr *saddr); +u8 ipv6_push_frag_opts (struct sk_buff *skb,struct ipv6_txoptions *opt, +u8 proto);int ipv6_skip_exthdr (const struct sk_buff *,int start,u8 *nexthdrp,__be16 *frag_offp);
net/ipv6/exthdrs.c +29 -26
109 lines not on this page · raw message
net/ipv6/ip6_output.c +11 -8
@@ -307,11 +307,12 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, seg_len += opt->opt_nflen + opt->opt_flen;if (opt->opt_flen) -ipv6_push_frag_opts (skb, opt, &proto); + proto =ipv6_push_frag_opts (skb, opt, proto);if (opt->opt_nflen) -ipv6_push_nfrag_opts (skb, opt, &proto, &first_hop, - &fl6->saddr); + proto =ipv6_push_nfrag_opts (skb, opt, proto, + &first_hop, + &fl6->saddr); }if (unlikely (seg_len >IPV6_MAXPLEN )) {
@@ -1941,11 +1942,13 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,__skb_pull (skb,skb_network_header_len (skb)); final_dst = &fl6->daddr; -if (opt && opt->opt_flen) -ipv6_push_frag_opts (skb, opt, &proto); -if (opt && opt->opt_nflen) -ipv6_push_nfrag_opts (skb, opt, &proto, &final_dst, &fl6->saddr); - +if (opt) { +if (opt->opt_flen) + proto =ipv6_push_frag_opts (skb, opt, proto); +if (opt->opt_nflen) + proto =ipv6_push_nfrag_opts (skb, opt, proto, + &final_dst, &fl6->saddr); + }skb_push (skb,sizeof (struct ipv6hdr ));skb_reset_network_header (skb); hdr =ipv6_hdr (skb);
net/ipv6/ip6_tunnel.c +1 -1
@@ -1273,7 +1273,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,if (encap_limit >=0 ) {init_tel_txopt (&opt, encap_limit); -ipv6_push_frag_opts (skb, &opt.ops, &proto); + proto =ipv6_push_frag_opts (skb, &opt.ops, proto); }skb_push (skb,sizeof (struct ipv6hdr ));
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/6 ipv6: add some unlikely()/likely() clauses in ip6_output.c
From: Eric Dumazet <[email protected]>
[ Upstream commit 2855e4925416c5900a9c6cece11f4a2e56bf6e63 ]
1) daddr is unlikely a multicast in ip6_finish_output2().
2) ip6_finish_output_gso_slowpath_drop() should not be called often.
3) ip6_fragment() should not be called often.
4) opt is unlikely to be set.
5) ip6_xmit() and ip6_forward() mostly sends not too big packets.
6) Most __ip6_make_skb() calls are for UDP packets, not ICMPV6 ones.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- net/ipv6/ip6_output.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
net/ipv6/ip6_output.c +12 -12
@@ -80,7 +80,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * hdr =ipv6_hdr (skb); daddr = &hdr->daddr; -if (ipv6_addr_is_multicast (daddr)) { +if (unlikely (ipv6_addr_is_multicast (daddr))) { if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(sk) && ((mroute6_is_socket(net, skb) && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
@@ -181,8 +181,8 @@ ip6_finish_output_gso_slowpath_drop(struct net *net, struct sock *sk,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)) +if (unlikely (!(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);
@@ -204,8 +204,8 @@ static int __ip6_finish_output(struct net *net, struct sock *sk, struct sk_buffif (skb_is_gso (skb))return ip6_finish_output_gso (net, sk, skb, mtu); -if (skb->len > mtu || - (IP6CB (skb)->frag_max_size && skb->len >IP6CB (skb)->frag_max_size)) +if (unlikely (skb->len > mtu || + (IP6CB (skb)->frag_max_size && skb->len >IP6CB (skb)->frag_max_size)))return ip6_fragment (net, sk, skb, ip6_finish_output2);return ip6_finish_output2 (net, sk, skb);
@@ -303,7 +303,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, } } -if (opt) { +if (unlikely (opt)) { seg_len += opt->opt_nflen + opt->opt_flen;if (opt->opt_flen)
@@ -356,7 +356,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, skb->mark = mark; mtu =dst_mtu (dst); -if ((skb->len <= mtu) || skb->ignore_df ||skb_is_gso (skb)) { +if (likely ((skb->len <= mtu) || skb->ignore_df ||skb_is_gso (skb))) {IP6_INC_STATS (net, idev,IPSTATS_MIB_OUTREQUESTS );/* if egress device is enslaved to an L3 master device pass the
@@ -656,7 +656,7 @@ int ip6_forward(struct sk_buff *skb)if (mtu <IPV6_MIN_MTU ) mtu =IPV6_MIN_MTU ; -if (ip6_pkt_too_big (skb, mtu)) { +if (unlikely (ip6_pkt_too_big (skb, mtu))) {/* Again, force OUTPUT device used as source address */ skb->dev = dev;icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu);
@@ -1370,7 +1370,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,/* * setup for corking */ -if (opt) { +if (unlikely (opt)) {if (WARN_ON (v6_cork->opt))return -EINVAL ;
@@ -1886,7 +1886,7 @@ static void ip6_cork_steal_dst(struct sk_buff *skb, struct inet_cork_full *cork)static void ip6_cork_release (struct inet_cork_full *cork,struct inet6_cork *v6_cork) { -if (v6_cork->opt) { +if (unlikely (v6_cork->opt)) {struct ipv6_txoptions *opt = v6_cork->opt;kfree (opt->dst0opt);
@@ -1942,7 +1942,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,__skb_pull (skb,skb_network_header_len (skb)); final_dst = &fl6->daddr; -if (opt) { +if (unlikely (opt)) {if (opt->opt_flen) proto =ipv6_push_frag_opts (skb, opt, proto);if (opt->opt_nflen)
@@ -1970,7 +1970,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,ip6_cork_steal_dst (skb, cork);IP6_INC_STATS (net, rt->rt6i_idev,IPSTATS_MIB_OUTREQUESTS ); -if (proto ==IPPROTO_ICMPV6 ) { +if (unlikely (proto ==IPPROTO_ICMPV6 )) {struct inet6_dev *idev =ip6_dst_idev (skb_dst (skb));u8 icmp6_type;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/6 inet: add dst4_mtu() and dst6_mtu() helpers
In reply to Sasha LevinFrom: Eric Dumazet <[email protected]>
[ Upstream commit 8776c4ef3ab22b95f55713f00a7a576e6402507d ]
With CONFIG_MITIGATION_RETPOLINE=y dst_mtu() is a bit fat, because it is generic.
Indeed, clang does not always inline it.
Add dst4_mtu() and dst6_mtu() helpers for callers that expect either ipv4_mtu() or ip6_mtu() to be called.
These helpers are always inlined.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- include/net/dst.h | 6 ++++++ include/net/ip6_route.h | 6 ++++++ 2 files changed, 12 insertions(+)
include/net/dst.h +6 -0
@@ -219,6 +219,12 @@ static inline u32 dst_mtu(const struct dst_entry *dst)return INDIRECT_CALL_INET (dst->ops->mtu, ip6_mtu, ipv4_mtu, dst); } +/* Variant of dst_mtu() for IPv4 users. */ +static inline u32 dst4_mtu (const struct dst_entry *dst) +{ +return INDIRECT_CALL_1 (dst->ops->mtu, ipv4_mtu, dst); +} +/* RTT metrics are stored in milliseconds for user ABI, but used as jiffies */ static inline unsigned long dst_metric_rtt (const struct dst_entry *dst,int metric) {
include/net/ip6_route.h +6 -0
@@ -266,6 +266,12 @@ static inline bool ipv6_anycast_destination(const struct dst_entry *dst,int ip6_fragment (struct net *net,struct sock *sk,struct sk_buff *skb,int (*output)(struct net *,struct sock *,struct sk_buff *)); +/* Variant of dst_mtu() for IPv6 users */ +static inline u32 dst6_mtu (const struct dst_entry *dst) +{ +return INDIRECT_CALL_1 (dst->ops->mtu, ip6_mtu, dst); +} +static inline unsigned int ip6_skb_dst_mtu (const struct sk_buff *skb) { const struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ?
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/6 ipv6: use dst6_mtu() instead of dst_mtu()
In reply to Sasha LevinFrom: Eric Dumazet <[email protected]>
[ Upstream commit b40f0130a23b6bab8b359e158a40af81f11f14be ]
When we expect an IPv6 dst, use dst6_mtu() instead of dst_mtu() to save some code space.
Due to current dst6_mtu() implementation, only convert users in IPv6 stack.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- net/ipv6/ip6_gre.c | 2 +- net/ipv6/ip6_output.c | 6 +++--- net/ipv6/ip6_tunnel.c | 4 ++-- net/ipv6/ipv6_sockglue.c | 4 ++-- net/ipv6/route.c | 10 ++++++---- net/ipv6/tcp_ipv6.c | 9 +++++---- 6 files changed, 19 insertions(+), 16 deletions(-)
net/ipv6/ip6_gre.c +1 -1
@@ -1057,7 +1057,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,/* TooBig packet may have updated dst->dev's mtu */ if (!t->parms.collect_md && dst) { mtu =READ_ONCE (dst_dev (dst)->mtu); -if (dst_mtu (dst) > mtu) +if (dst6_mtu (dst) > mtu) dst->ops->update_pmtu (dst,NULL , skb, mtu, false); } err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
net/ipv6/ip6_output.c +3 -3
@@ -355,7 +355,7 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, skb->priority = priority; skb->mark = mark; - mtu =dst_mtu (dst); + mtu =dst6_mtu (dst);if (likely ((skb->len <= mtu) || skb->ignore_df ||skb_is_gso (skb))) {IP6_INC_STATS (net, idev,IPSTATS_MIB_OUTREQUESTS );
@@ -1405,10 +1405,10 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, v6_cork->dontfrag = ipc6->dontfrag;if (rt->dst.flags &DST_XFRM_TUNNEL ) mtu =READ_ONCE (np->pmtudisc) >=IPV6_PMTUDISC_PROBE ? -READ_ONCE (rt->dst.dev->mtu) :dst_mtu (&rt->dst); +READ_ONCE (rt->dst.dev->mtu) :dst6_mtu (&rt->dst);else mtu =READ_ONCE (np->pmtudisc) >=IPV6_PMTUDISC_PROBE ? -READ_ONCE (rt->dst.dev->mtu) :dst_mtu (xfrm_dst_path (&rt->dst)); +READ_ONCE (rt->dst.dev->mtu) :dst6_mtu (xfrm_dst_path (&rt->dst)); frag_size =READ_ONCE (np->frag_size);if (frag_size && frag_size < mtu)
net/ipv6/ip6_tunnel.c +2 -2
@@ -643,7 +643,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,/* change mtu on this route */ if (rel_type ==ICMP_DEST_UNREACH && rel_code ==ICMP_FRAG_NEEDED ) { -if (rel_info >dst_mtu (skb_dst (skb2))) +if (rel_info >dst6_mtu (skb_dst (skb2))) goto out;skb_dst_update_pmtu_no_confirm (skb2, rel_info);
@@ -1195,7 +1195,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, t->parms.name); goto tx_err_dst_release; } - mtu =dst_mtu (dst) - eth_hlen - psh_hlen - t->tun_hlen; + mtu =dst6_mtu (dst) - eth_hlen - psh_hlen - t->tun_hlen;if (encap_limit >=0 ) { max_headroom +=8 ; mtu -=8 ;
net/ipv6/ipv6_sockglue.c +2 -2
@@ -1184,7 +1184,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,rcu_read_lock (); dst =__sk_dst_get (sk);if (dst) - val =dst_mtu (dst); + val =dst6_mtu (dst);rcu_read_unlock ();if (!val)return -ENOTCONN ;
@@ -1283,7 +1283,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,rcu_read_lock (); dst =__sk_dst_get (sk);if (dst) - mtuinfo.ip6m_mtu =dst_mtu (dst); + mtuinfo.ip6m_mtu =dst6_mtu (dst);rcu_read_unlock ();if (!mtuinfo.ip6m_mtu)return -ENOTCONN ;
net/ipv6/route.c +6 -4
@@ -2053,6 +2053,8 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt)static bool rt6_mtu_change_route_allowed (struct inet6_dev *idev,struct rt6_info *rt,int mtu) { +u32 dmtu =dst6_mtu (&rt->dst); +/* If the new MTU is lower than the route PMTU, this new MTU will be the * lowest MTU in the path: always allow updating the route PMTU to * reflect PMTU decreases.
@@ -2063,10 +2065,10 @@ static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,* handle this. */ -if (dst_mtu (&rt->dst) >= mtu) +if (dmtu >= mtu)return true; -if (dst_mtu (&rt->dst) == idev->cnf.mtu6) +if (dmtu == idev->cnf.mtu6)return true;return false;
@@ -2936,7 +2938,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,if (mtu <IPV6_MIN_MTU )return ; -if (mtu >=dst_mtu (dst)) +if (mtu >=dst6_mtu (dst))return ;if (!rt6_cache_allowed_for_pmtu (rt6)) {
@@ -3252,7 +3254,7 @@ EXPORT_SYMBOL_GPL(ip6_sk_redirect);static unsigned int ip6_default_advmss (const struct dst_entry *dst) { -unsigned int mtu =dst_mtu (dst); +unsigned int mtu =dst6_mtu (dst);struct net *net; mtu -=sizeof (struct ipv6hdr ) +sizeof (struct tcphdr );
net/ipv6/tcp_ipv6.c +5 -4
@@ -351,7 +351,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,static void tcp_v6_mtu_reduced (struct sock *sk) {struct dst_entry *dst; -u32 mtu; +u32 mtu, dmtu;if ((1 << sk->sk_state) & (TCPF_LISTEN |TCPF_CLOSE ))return ;
@@ -368,8 +368,9 @@ static void tcp_v6_mtu_reduced(struct sock *sk)if (!dst)return ; -if (inet_csk (sk)->icsk_pmtu_cookie >dst_mtu (dst)) { -tcp_sync_mss (sk,dst_mtu (dst)); + dmtu =dst6_mtu (dst); +if (inet_csk (sk)->icsk_pmtu_cookie > dmtu) { +tcp_sync_mss (sk, dmtu);tcp_simple_retransmit (sk); } }
@@ -1499,7 +1500,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *tcp_ca_openreq_child (newsk, dst); -tcp_sync_mss (newsk,dst_mtu (dst)); +tcp_sync_mss (newsk,dst6_mtu (dst)); newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst));tcp_initialize_rcv_mss (newsk);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/6 ipv4: use dst4_mtu() instead of dst_mtu()
In reply to Sasha LevinFrom: Eric Dumazet <[email protected]>
[ Upstream commit fe8570186f100b6cc499b2f7705946baf1388cde ]
When we expect an IPv4 dst, use dst4_mtu() instead of dst_mtu() to save some code space.
Stable-dep-of: 870a9e42ecc6 ("tcp: clamp route advmss to TCP_MIN_MSS")
--- net/ipv4/icmp.c | 2 +- net/ipv4/ip_output.c | 4 ++-- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv4/netfilter/nf_reject_ipv4.c | 2 +- net/ipv4/tcp_ipv4.c | 13 ++++++------- net/ipv6/sit.c | 2 +- 7 files changed, 13 insertions(+), 14 deletions(-)
net/ipv4/icmp.c +1 -1
@@ -790,7 +790,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,/* RFC says return as much as we can without exceeding 576 bytes. */ - room =dst_mtu (&rt->dst); + room =dst4_mtu (&rt->dst);if (room >576 ) room =576 ; room -=sizeof (struct iphdr ) + icmp_param.replyopts.opt.opt.optlen;
net/ipv4/ip_output.c +2 -2
@@ -1303,7 +1303,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,return -EFAULT ; cork->fragsize =ip_sk_use_pmtu (sk) ? -dst_mtu (&rt->dst) :READ_ONCE (rt->dst.dev->mtu); +dst4_mtu (&rt->dst) :READ_ONCE (rt->dst.dev->mtu);if (!inetdev_valid_mtu (cork->fragsize))return -ENETUNREACH ;
@@ -1442,7 +1442,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk, pmtudisc =READ_ONCE (inet->pmtudisc);if (pmtudisc ==IP_PMTUDISC_DO || pmtudisc ==IP_PMTUDISC_PROBE || - (skb->len <=dst_mtu (&rt->dst) && + (skb->len <=dst4_mtu (&rt->dst) &&ip_dont_fragment (sk, &rt->dst))) df =htons (IP_DF );
net/ipv4/ip_sockglue.c +1 -1
@@ -1634,7 +1634,7 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, val =0 ; dst =sk_dst_get (sk);if (dst) { - val =dst_mtu (dst); + val =dst4_mtu (dst);dst_release (dst); }if (!val)
net/ipv4/ipmr.c +1 -1
@@ -1895,7 +1895,7 @@ static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,return -1 ; } -if (skb->len+encap >dst_mtu (&rt->dst) && (ntohs (iph->frag_off) &IP_DF )) { +if (skb->len+encap >dst4_mtu (&rt->dst) && (ntohs (iph->frag_off) &IP_DF )) {/* Do not fragment multicasts. Alas, IPv4 does not * allow to send ICMP, so that packets will disappear * to blackhole.
net/ipv4/netfilter/nf_reject_ipv4.c +1 -1
@@ -303,7 +303,7 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb, goto free_nskb;/* "Never happens" */ -if (nskb->len >dst_mtu (skb_dst (nskb))) +if (nskb->len >dst4_mtu (skb_dst (nskb))) goto free_nskb;nf_ct_attach (nskb, oldskb);
net/ipv4/tcp_ipv4.c +6 -7
@@ -373,7 +373,7 @@ void tcp_v4_mtu_reduced(struct sock *sk) {struct inet_sock *inet =inet_sk (sk);struct dst_entry *dst; -u32 mtu; +u32 mtu, dmtu;if ((1 << sk->sk_state) & (TCPF_LISTEN |TCPF_CLOSE ))return ;
@@ -385,15 +385,14 @@ void tcp_v4_mtu_reduced(struct sock *sk)/* Something is about to be wrong... Remember soft error * for the case, if this connection will not able to recover. */ -if (mtu <dst_mtu (dst) &&ip_dont_fragment (sk, dst)) + dmtu =dst4_mtu (dst); +if (mtu < dmtu &&ip_dont_fragment (sk, dst))WRITE_ONCE (sk->sk_err_soft,EMSGSIZE ); - mtu =dst_mtu (dst); -if (inet->pmtudisc !=IP_PMTUDISC_DONT &&ip_sk_accept_pmtu (sk) && -inet_csk (sk)->icsk_pmtu_cookie > mtu) { -tcp_sync_mss (sk, mtu); +inet_csk (sk)->icsk_pmtu_cookie > dmtu) { +tcp_sync_mss (sk, dmtu);/* Resend the TCP packet because it's * clear that the old packet has been
@@ -1817,7 +1816,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,#endif tcp_ca_openreq_child (newsk, dst); -tcp_sync_mss (newsk,dst_mtu (dst)); +tcp_sync_mss (newsk,dst4_mtu (dst)); newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst));tcp_initialize_rcv_mss (newsk);
net/ipv6/sit.c +1 -1
@@ -963,7 +963,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, iph6 =ipv6_hdr (skb);if (df) { - mtu =dst_mtu (&rt->dst) - t_hlen; + mtu =dst4_mtu (&rt->dst) - t_hlen;if (mtu <IPV4_MIN_MTU ) {DEV_STATS_INC (dev, collisions);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 6/6 tcp: clamp route advmss to TCP_MIN_MSS
In reply to Sasha LevinFrom: Yong Wang <[email protected]>
[ Upstream commit 870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1 ]
tcp_select_initial_window() assumes that callers never pass an MSS smaller than 1, but route-derived advmss values can violate that assumption.
A too-small explicit RTAX_ADVMSS is one way to get there, but it is not the only one. The same divide-by-zero can also be reached through the "default advmss" path when RTAX_ADVMSS is left at 0 and the effective advmss is later driven down by route MTU and min_adv_mss.
Introduce a tcp_dst_advmss() helper that clamps route advmss to TCP_MIN_MSS before TCP consumes it, and use it in the TCP paths that derive advmss from dst metrics. This keeps the effective MSS from dropping to zero before tcp_select_initial_window() rounds the receive window.
--- include/net/tcp.h | 5 +++++ net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 6 +++--- net/ipv6/tcp_ipv6.c | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-)
include/net/tcp.h +5 -0
@@ -1686,6 +1686,11 @@ static inline int tcp_full_space(const struct sock *sk)return tcp_win_from_space (sk,READ_ONCE (sk->sk_rcvbuf)); } +static inline u32 tcp_dst_advmss (const struct dst_entry *dst) +{ +return max_t (u32,dst_metric_advmss (dst),TCP_MIN_MSS ); +} +static inline void __tcp_adjust_rcv_ssthresh (struct sock *sk,u32 new_ssthresh) {int unused_mem =sk_unused_reserved_mem (sk);
net/ipv4/tcp_ipv4.c +1 -1
@@ -1817,7 +1817,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst4_mtu (dst)); - newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst)); + newtp->advmss =tcp_mss_clamp (tcp_sk (sk),tcp_dst_advmss (dst));tcp_initialize_rcv_mss (newsk);
net/ipv4/tcp_minisocks.c +1 -1
@@ -445,7 +445,7 @@ void tcp_openreq_init_rwin(struct request_sock *req,u32 rcv_wnd;int mss; - mss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + mss =tcp_mss_clamp (tp,tcp_dst_advmss (dst)); window_clamp =READ_ONCE (tp->window_clamp);/* Set this up on the first call only */ req->rsk_window_clamp = window_clamp ? :dst_metric (dst,RTAX_WINDOW );
net/ipv4/tcp_output.c +3 -3
@@ -129,7 +129,7 @@ static __u16 tcp_advertise_mss(struct sock *sk)int mss = tp->advmss;if (dst) { -unsigned int metric =dst_metric_advmss (dst); +unsigned int metric =tcp_dst_advmss (dst);if (metric < mss) { mss = metric;
@@ -3906,7 +3906,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, }skb_dst_set (skb, dst); - mss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + mss =tcp_mss_clamp (tp,tcp_dst_advmss (dst));memset (&opts,0 ,sizeof (opts)); now =tcp_clock_ns ();
@@ -4062,7 +4062,7 @@ static void tcp_connect_init(struct sock *sk)if (!tp->window_clamp)WRITE_ONCE (tp->window_clamp,dst_metric (dst,RTAX_WINDOW )); - tp->advmss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + tp->advmss =tcp_mss_clamp (tp,tcp_dst_advmss (dst));tcp_initialize_rcv_mss (sk);
net/ipv6/tcp_ipv6.c +1 -1
@@ -1501,7 +1501,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst6_mtu (dst)); - newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst)); + newtp->advmss =tcp_mss_clamp (tcp_sk (sk),tcp_dst_advmss (dst));tcp_initialize_rcv_mss (newsk);
Signature · 1 line
2.53.0