From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 352B851DB19; Wed, 30 Sep 2026 17:44:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790790278; cv=none; b=ka/9lp1/8CzN1N1nJFbJ8daeCLGUHXZn7f+etva0Cn1EtaoCDSY//PC8vyYCNFuqYz0O9RuwkII8dzSiGZ7x0ZWkQ+TKT1iD2tnh4g62LUq9RZABCsp7Dc5iuOK4Z9QD966gactpDv7unGofzYRs/Wwy2ixrZ/dSka0inqwysAA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790790278; c=relaxed/simple; bh=Y3LW1JwmwdJtPhaZrBWRPAut2Ufbuutl89qaZR70AMI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dyQ5YX5GwrmmmnGPQMwh68R4PGuUiKWAZ1t7AZO73NMaHOZfrdnWhIXqFbNR4Wqpz+HGwU05t56id3Jd4Gh+yaAEV/wrGZSJFvPWuHQ+UkrfRtfoM/xwCkYqUeUQZJEcI54ULGllVoS6/HcTlo8iPYzBqY/FN5XqCxEGSmRjFVU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=tZDzWoBs; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="tZDzWoBs" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8E2AD1F000FF; Wed, 30 Sep 2026 17:44:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1790790276; bh=R1rvRZhxCeYTxgAQFEDxQdyZN6RH/WCuRn7qJxRXhaQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=tZDzWoBstl4FxeKHc/oxgPT/RdzOcDqD1p0A8EiCANXPrcYyl0h1wwRvDf/EJTvzb NH2ww4MWV7EjgBLYXKkjt/aTmaLydBJJlAW4gVmvh9aagfA1S/Iry+9zVEWUyDyOUm Qt+BLbjnhinPgsDO3D1Hhm20vYP272Gdl8/1ompI= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Eric Dumazet , Kuniyuki Iwashima , Jakub Kicinski , Sasha Levin Subject: [PATCH 6.12 771/877] tcp: introduce icsk->icsk_keepalive_timer Date: Wed, 30 Sep 2026 17:28:02 +0200 Message-ID: <20260930152431.350990551@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260930152414.738996857@linuxfoundation.org> References: <20260930152414.738996857@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Eric Dumazet [ Upstream commit 08dfe370239e53494453cee1e2ded2cdaa1efd12 ] sk->sk_timer has been used for TCP keepalives. Keepalive timers are not in fast path, we want to use sk->sk_timer storage for retransmit timers, for better cache locality. Create icsk->icsk_keepalive_timer and change keepalive code to no longer use sk->sk_timer. Added space is reclaimed in the following patch. This includes changes to MPTCP, which was also using sk_timer. Alias icsk->mptcp_tout_timer and icsk->icsk_keepalive_timer for inet_sk_diag_fill() sake. Signed-off-by: Eric Dumazet Reviewed-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20251124175013.1473655-4-edumazet@google.com Signed-off-by: Jakub Kicinski Stable dependency adaptation for e2ab913f68c7d11e2561b8a8ad0b87ffefcad667: Retain the 6.12 from_timer() API, icsk_timeout fields, documentation format and existing inet_csk_{reset,delete}_keepalive_timer() helpers. Convert the DCCP keepalive callback as well, since DCCP still shares the inet_csk timer initialization on this branch. Do not add TCP-only timer helper functions from newer kernels. Include the MPTCP portion of 9a5e5334adc03: alias sk_timer storage as mptcp_retransmit_timer and migrate every MPTCP retransmit timer user. TCP and DCCP retain their existing icsk_retransmit_timer storage. Adapt the fallback accounting preparation from c65c2e3bae69, authored by Paolo Abeni. Move the existing __mptcp_try_fallback() from protocol.h to protocol.c, pass its fallback MIB through the existing callers, and add the matching counters. Preserve the mptcp_subflow_early_fallback() name and use the stable simultaneous-connect and blackhole fallback paths. This supplies the fallback-helper context expected by the target. No new functions are introduced. The target's RTX enable-bit fix remains in the target commit; this dependency only prepares its application. Stable-dep-of: e2ab913f68c7 ("mptcp: do not reschedule the RTX timer for fallback sockets") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/networking/net_cachelines/inet_connection_sock.rst | 1 include/net/inet_connection_sock.h | 11 + include/net/sock.h | 6 net/dccp/timer.c | 4 net/ipv4/inet_connection_sock.c | 10 - net/ipv4/inet_diag.c | 4 net/ipv4/tcp_ipv4.c | 4 net/ipv4/tcp_timer.c | 5 net/ipv6/tcp_ipv6.c | 4 net/mptcp/ctrl.c | 4 net/mptcp/mib.c | 5 net/mptcp/mib.h | 5 net/mptcp/options.c | 6 net/mptcp/protocol.c | 70 +++++----- net/mptcp/protocol.h | 31 +--- net/mptcp/subflow.c | 10 - tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c | 4 tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c | 4 18 files changed, 107 insertions(+), 81 deletions(-) --- a/Documentation/networking/net_cachelines/inet_connection_sock.rst +++ b/Documentation/networking/net_cachelines/inet_connection_sock.rst @@ -14,6 +14,7 @@ struct_inet_bind2_bucket icsk unsigned_long icsk_timeout read_mostly - inet_csk_reset_xmit_timer,tcp_connect struct_timer_list icsk_retransmit_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect struct_timer_list icsk_delack_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect +struct_timer_list icsk_keepalive_timer - - u32 icsk_rto read_write - tcp_cwnd_validate,tcp_schedule_loss_probe,tcp_connect_init,tcp_connect,tcp_write_xmit,tcp_push_one u32 icsk_rto_min - - u32 icsk_delack_max - - --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -62,6 +62,9 @@ struct inet_connection_sock_af_ops { * @icsk_bind2_hash: Bind node in the bhash2 table * @icsk_timeout: Timeout * @icsk_retransmit_timer: Resend (no ack) + * @icsk_delack_timer: Delayed ACK timer + * @icsk_keepalive_timer: Keepalive timer + * @mptcp_tout_timer: MPTCP timeout timer * @icsk_rto: Retransmit timeout * @icsk_pmtu_cookie Last pmtu seen by socket * @icsk_ca_ops Pluggable congestion control hook @@ -88,8 +91,12 @@ struct inet_connection_sock { struct inet_bind_bucket *icsk_bind_hash; struct inet_bind2_bucket *icsk_bind2_hash; unsigned long icsk_timeout; - struct timer_list icsk_retransmit_timer; - struct timer_list icsk_delack_timer; + struct timer_list icsk_retransmit_timer; + struct timer_list icsk_delack_timer; + union { + struct timer_list icsk_keepalive_timer; + struct timer_list mptcp_tout_timer; + }; __u32 icsk_rto; __u32 icsk_rto_min; __u32 icsk_delack_max; --- a/include/net/sock.h +++ b/include/net/sock.h @@ -300,6 +300,7 @@ struct sk_filter; * @sk_txrehash: enable TX hash rethink * @sk_filter: socket filtering instructions * @sk_timer: sock cleanup timer + * @mptcp_retransmit_timer: MPTCP retransmit timer * @sk_stamp: time stamp of last packet received * @sk_stamp_seq: lock for accessing sk_stamp on 32 bit architectures only * @sk_tsflags: SO_TIMESTAMPING flags @@ -465,7 +466,10 @@ struct sock { u32 sk_dst_pending_confirm; u32 sk_pacing_status; /* see enum sk_pacing */ struct page_frag sk_frag; - struct timer_list sk_timer; + union { + struct timer_list sk_timer; + struct timer_list mptcp_retransmit_timer; + }; unsigned long sk_pacing_rate; /* bytes per second */ atomic_t sk_zckey; --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -160,7 +160,9 @@ out: static void dccp_keepalive_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_keepalive_timer); + struct sock *sk = &icsk->icsk_inet.sk; pr_err("dccp should not use a keepalive timer !\n"); sock_put(sk); --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -750,7 +750,7 @@ void inet_csk_init_xmit_timers(struct so timer_setup(&icsk->icsk_retransmit_timer, retransmit_handler, 0); timer_setup(&icsk->icsk_delack_timer, delack_handler, 0); - timer_setup(&sk->sk_timer, keepalive_handler, 0); + timer_setup(&icsk->icsk_keepalive_timer, keepalive_handler, 0); icsk->icsk_pending = icsk->icsk_ack.pending = 0; } EXPORT_SYMBOL(inet_csk_init_xmit_timers); @@ -763,7 +763,7 @@ void inet_csk_clear_xmit_timers(struct s sk_stop_timer(sk, &icsk->icsk_retransmit_timer); sk_stop_timer(sk, &icsk->icsk_delack_timer); - sk_stop_timer(sk, &sk->sk_timer); + sk_stop_timer(sk, &icsk->icsk_keepalive_timer); } EXPORT_SYMBOL(inet_csk_clear_xmit_timers); @@ -778,18 +778,18 @@ void inet_csk_clear_xmit_timers_sync(str sk_stop_timer_sync(sk, &icsk->icsk_retransmit_timer); sk_stop_timer_sync(sk, &icsk->icsk_delack_timer); - sk_stop_timer_sync(sk, &sk->sk_timer); + sk_stop_timer_sync(sk, &icsk->icsk_keepalive_timer); } void inet_csk_delete_keepalive_timer(struct sock *sk) { - sk_stop_timer(sk, &sk->sk_timer); + sk_stop_timer(sk, &inet_csk(sk)->icsk_keepalive_timer); } EXPORT_SYMBOL(inet_csk_delete_keepalive_timer); void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len) { - sk_reset_timer(sk, &sk->sk_timer, jiffies + len); + sk_reset_timer(sk, &inet_csk(sk)->icsk_keepalive_timer, jiffies + len); } EXPORT_SYMBOL(inet_csk_reset_keepalive_timer); --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -319,11 +319,11 @@ int inet_sk_diag_fill(struct sock *sk, s r->idiag_retrans = icsk->icsk_probes_out; r->idiag_expires = jiffies_delta_to_msecs(icsk->icsk_timeout - jiffies); - } else if (timer_pending(&sk->sk_timer)) { + } else if (timer_pending(&icsk->icsk_keepalive_timer)) { r->idiag_timer = 2; r->idiag_retrans = icsk->icsk_probes_out; r->idiag_expires = - jiffies_delta_to_msecs(sk->sk_timer.expires - jiffies); + jiffies_delta_to_msecs(icsk->icsk_keepalive_timer.expires - jiffies); } if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) { --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2918,9 +2918,9 @@ static void get_tcp4_sock(struct sock *s } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { timer_active = 4; timer_expires = icsk->icsk_timeout; - } else if (timer_pending(&sk->sk_timer)) { + } else if (timer_pending(&icsk->icsk_keepalive_timer)) { timer_active = 2; - timer_expires = sk->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; } else { timer_active = 0; timer_expires = jiffies; --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -755,8 +755,9 @@ EXPORT_IPV6_MOD_GPL(tcp_set_keepalive); static void tcp_keepalive_timer (struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); - struct inet_connection_sock *icsk = inet_csk(sk); + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_keepalive_timer); + struct sock *sk = &icsk->icsk_inet.sk; struct tcp_sock *tp = tcp_sk(sk); u32 elapsed; --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2179,9 +2179,9 @@ static void get_tcp6_sock(struct seq_fil } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { timer_active = 4; timer_expires = icsk->icsk_timeout; - } else if (timer_pending(&sp->sk_timer)) { + } else if (timer_pending(&icsk->icsk_keepalive_timer)) { timer_active = 2; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; } else { timer_active = 0; timer_expires = jiffies; --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -407,9 +407,9 @@ void mptcp_active_detect_blackhole(struc if (subflow->request_mptcp && ssk->sk_state == TCP_SYN_SENT) { if (timeouts == 2 || (timeouts < 2 && expired)) { - MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDROP); subflow->mpc_drop = 1; - mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow); + mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow, + MPTCP_MIB_MPCAPABLEACTIVEDROP); } } else if (ssk->sk_state == TCP_SYN_SENT) { subflow->mpc_drop = 0; --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -79,6 +79,11 @@ static const struct snmp_mib mptcp_snmp_ SNMP_MIB_ITEM("RcvWndConflict", MPTCP_MIB_RCVWNDCONFLICT), SNMP_MIB_ITEM("MPCurrEstab", MPTCP_MIB_CURRESTAB), SNMP_MIB_ITEM("Blackhole", MPTCP_MIB_BLACKHOLE), + SNMP_MIB_ITEM("MPCapableDataFallback", MPTCP_MIB_MPCAPABLEDATAFALLBACK), + SNMP_MIB_ITEM("MD5SigFallback", MPTCP_MIB_MD5SIGFALLBACK), + SNMP_MIB_ITEM("DssFallback", MPTCP_MIB_DSSFALLBACK), + SNMP_MIB_ITEM("SimultConnectFallback", MPTCP_MIB_SIMULTCONNFALLBACK), + SNMP_MIB_ITEM("FallbackFailed", MPTCP_MIB_FALLBACKFAILED), SNMP_MIB_SENTINEL }; --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -80,6 +80,11 @@ enum linux_mptcp_mib_field { MPTCP_MIB_RCVWNDCONFLICT, /* Conflict with while updating msk rcv wnd */ MPTCP_MIB_CURRESTAB, /* Current established MPTCP connections */ MPTCP_MIB_BLACKHOLE, /* A blackhole has been detected */ + MPTCP_MIB_MPCAPABLEDATAFALLBACK, /* No DSS/MPC+data on first established packet */ + MPTCP_MIB_MD5SIGFALLBACK, /* Conflicting TCP option enabled */ + MPTCP_MIB_DSSFALLBACK, /* Bad or missing DSS */ + MPTCP_MIB_SIMULTCONNFALLBACK, /* Simultaneous connect */ + MPTCP_MIB_FALLBACKFAILED, /* Can't fallback due to msk status */ __MPTCP_MIB_MAX }; --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -473,7 +473,7 @@ bool mptcp_syn_options(struct sock *sk, subflow->snd_isn = TCP_SKB_CB(skb)->end_seq; if (subflow->request_mptcp) { if (unlikely(subflow_simultaneous_connect(sk))) { - WARN_ON_ONCE(!mptcp_try_fallback(sk)); + WARN_ON_ONCE(!mptcp_try_fallback(sk, MPTCP_MIB_SIMULTCONNFALLBACK)); /* Ensure mptcp_finish_connect() will not process the * MPC handshake. @@ -1043,8 +1043,10 @@ static bool check_fully_established(stru if (subflow->mp_join) goto reset; subflow->mp_capable = 0; - if (!mptcp_try_fallback(ssk)) + if (!mptcp_try_fallback(ssk, MPTCP_MIB_MPCAPABLEDATAFALLBACK)) { + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_FALLBACKFAILED); goto reset; + } pr_fallback(msk); return false; } --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -67,6 +67,26 @@ static const struct proto_ops *mptcp_fal return &inet_stream_ops; } +bool __mptcp_try_fallback(struct mptcp_sock *msk, int fb_mib) +{ + struct net *net = sock_net((struct sock *)msk); + + if (__mptcp_check_fallback(msk)) + return true; + + spin_lock_bh(&msk->fallback_lock); + if (!msk->allow_infinite_fallback) { + spin_unlock_bh(&msk->fallback_lock); + return false; + } + + msk->allow_subflows = false; + set_bit(MPTCP_FALLBACK_DONE, &msk->flags); + __MPTCP_INC_STATS(net, fb_mib); + spin_unlock_bh(&msk->fallback_lock); + return true; +} + static int __mptcp_socket_create(struct mptcp_sock *msk) { struct mptcp_subflow_context *subflow; @@ -414,9 +434,7 @@ static bool __mptcp_move_skb(struct sock static void mptcp_stop_rtx_timer(struct sock *sk) { - struct inet_connection_sock *icsk = inet_csk(sk); - - sk_stop_timer(sk, &icsk->icsk_retransmit_timer); + sk_stop_timer(sk, &sk->mptcp_retransmit_timer); mptcp_sk(sk)->timer_ival = 0; } @@ -659,10 +677,7 @@ static bool mptcp_check_data_fin(struct static void mptcp_dss_corruption(struct mptcp_sock *msk, struct sock *ssk) { - if (mptcp_try_fallback(ssk)) { - MPTCP_INC_STATS(sock_net(ssk), - MPTCP_MIB_DSSCORRUPTIONFALLBACK); - } else { + if (!mptcp_try_fallback(ssk, MPTCP_MIB_DSSCORRUPTIONFALLBACK)) { MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DSSCORRUPTIONRESET); mptcp_subflow_reset(ssk); } @@ -973,12 +988,11 @@ static void __mptcp_flush_join_list(stru static bool mptcp_rtx_timer_pending(struct sock *sk) { - return timer_pending(&inet_csk(sk)->icsk_retransmit_timer); + return timer_pending(&sk->mptcp_retransmit_timer); } static void mptcp_reset_rtx_timer(struct sock *sk) { - struct inet_connection_sock *icsk = inet_csk(sk); unsigned long tout; /* prevent rescheduling on close */ @@ -986,7 +1000,7 @@ static void mptcp_reset_rtx_timer(struct return; tout = mptcp_sk(sk)->timer_ival; - sk_reset_timer(sk, &icsk->icsk_retransmit_timer, jiffies + tout); + sk_reset_timer(sk, &sk->mptcp_retransmit_timer, jiffies + tout); } bool mptcp_schedule_work(struct sock *sk) @@ -1293,12 +1307,12 @@ static void mptcp_update_infinite_map(st mpext->infinite_map = 1; mpext->data_len = 0; - if (!mptcp_try_fallback(ssk)) { + if (!mptcp_try_fallback(ssk, MPTCP_MIB_INFINITEMAPTX)) { + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_FALLBACKFAILED); mptcp_subflow_reset(ssk); return; } - MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPTX); mptcp_subflow_ctx(ssk)->send_infinite_map = 0; pr_fallback(msk); } @@ -2393,9 +2407,7 @@ out_err: static void mptcp_retransmit_timer(struct timer_list *t) { - struct inet_connection_sock *icsk = from_timer(icsk, t, - icsk_retransmit_timer); - struct sock *sk = &icsk->icsk_inet.sk; + struct sock *sk = from_timer(sk, t, mptcp_retransmit_timer); struct mptcp_sock *msk = mptcp_sk(sk); bh_lock_sock(sk); @@ -2413,7 +2425,9 @@ static void mptcp_retransmit_timer(struc static void mptcp_tout_timer(struct timer_list *t) { - struct sock *sk = from_timer(sk, t, sk_timer); + struct inet_connection_sock *icsk = + from_timer(icsk, t, mptcp_tout_timer); + struct sock *sk = &icsk->icsk_inet.sk; mptcp_schedule_work(sk); sock_put(sk); @@ -2856,7 +2870,7 @@ void mptcp_reset_tout_timer(struct mptcp */ timeout = inet_csk(sk)->icsk_mtup.probe_timestamp ? close_timeout : fail_tout; - sk_reset_timer(sk, &sk->sk_timer, timeout); + sk_reset_timer(sk, &inet_csk(sk)->mptcp_tout_timer, timeout); } static void mptcp_mp_fail_no_response(struct mptcp_sock *msk) @@ -2988,9 +3002,8 @@ static void __mptcp_init_sock(struct soc mptcp_pm_data_init(msk); spin_lock_init(&msk->fallback_lock); - /* re-use the csk retrans timer for MPTCP-level retrans */ - timer_setup(&msk->sk.icsk_retransmit_timer, mptcp_retransmit_timer, 0); - timer_setup(&sk->sk_timer, mptcp_tout_timer, 0); + timer_setup(&sk->mptcp_retransmit_timer, mptcp_retransmit_timer, 0); + timer_setup(&msk->sk.mptcp_tout_timer, mptcp_tout_timer, 0); } static void mptcp_ca_reset(struct sock *sk) @@ -3192,7 +3205,7 @@ static void __mptcp_destroy_sock(struct might_sleep(); mptcp_stop_rtx_timer(sk); - sk_stop_timer(sk, &sk->sk_timer); + sk_stop_timer(sk, &inet_csk(sk)->mptcp_tout_timer); msk->pm.status = 0; mptcp_release_sched(msk); @@ -3938,16 +3951,15 @@ static int mptcp_connect(struct sock *sk * TCP option space. */ if (rcu_access_pointer(tcp_sk(ssk)->md5sig_info)) - mptcp_subflow_early_fallback(msk, subflow); + mptcp_subflow_early_fallback(msk, subflow, MPTCP_MIB_MD5SIGFALLBACK); #endif if (subflow->request_mptcp) { - if (mptcp_active_should_disable(sk)) { - MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDISABLED); - mptcp_subflow_early_fallback(msk, subflow); - } else if (mptcp_token_new_connect(ssk) < 0) { - MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_TOKENFALLBACKINIT); - mptcp_subflow_early_fallback(msk, subflow); - } + if (mptcp_active_should_disable(sk)) + mptcp_subflow_early_fallback(msk, subflow, + MPTCP_MIB_MPCAPABLEACTIVEDISABLED); + else if (mptcp_token_new_connect(ssk) < 0) + mptcp_subflow_early_fallback(msk, subflow, + MPTCP_MIB_TOKENFALLBACKINIT); } WRITE_ONCE(msk->write_seq, subflow->idsn); --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -845,7 +845,7 @@ static inline void mptcp_stop_tout_timer if (!inet_csk(sk)->icsk_mtup.probe_timestamp) return; - sk_stop_timer(sk, &sk->sk_timer); + sk_stop_timer(sk, &inet_csk(sk)->mptcp_tout_timer); inet_csk(sk)->icsk_mtup.probe_timestamp = 0; } @@ -1216,24 +1216,6 @@ static inline bool mptcp_check_fallback( return __mptcp_check_fallback(msk); } -static inline bool __mptcp_try_fallback(struct mptcp_sock *msk) -{ - if (__mptcp_check_fallback(msk)) { - pr_debug("TCP fallback already done (msk=%p)\n", msk); - return true; - } - spin_lock_bh(&msk->fallback_lock); - if (!msk->allow_infinite_fallback) { - spin_unlock_bh(&msk->fallback_lock); - return false; - } - - msk->allow_subflows = false; - set_bit(MPTCP_FALLBACK_DONE, &msk->flags); - spin_unlock_bh(&msk->fallback_lock); - return true; -} - static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk) { struct sock *ssk = READ_ONCE(msk->first); @@ -1243,14 +1225,16 @@ static inline bool __mptcp_has_initial_s TCPF_SYN_RECV | TCPF_LISTEN)); } -static inline bool mptcp_try_fallback(struct sock *ssk) +bool __mptcp_try_fallback(struct mptcp_sock *msk, int fb_mib); + +static inline bool mptcp_try_fallback(struct sock *ssk, int fb_mib) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); struct sock *sk = subflow->conn; struct mptcp_sock *msk; msk = mptcp_sk(sk); - if (!__mptcp_try_fallback(msk)) + if (!__mptcp_try_fallback(msk, fb_mib)) return false; if (READ_ONCE(msk->snd_data_fin_enable) && !(ssk->sk_shutdown & SEND_SHUTDOWN)) { gfp_t saved_allocation = ssk->sk_allocation; @@ -1269,11 +1253,12 @@ static inline bool mptcp_try_fallback(st #define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)\n", __func__, a) static inline void mptcp_subflow_early_fallback(struct mptcp_sock *msk, - struct mptcp_subflow_context *subflow) + struct mptcp_subflow_context *subflow, + int fb_mib) { pr_fallback(msk); subflow->request_mptcp = 0; - WARN_ON_ONCE(!__mptcp_try_fallback(msk)); + WARN_ON_ONCE(!__mptcp_try_fallback(msk, fb_mib)); } static inline bool mptcp_check_infinite_map(struct sk_buff *skb) --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -550,11 +550,13 @@ static void subflow_finish_connect(struc mptcp_get_options(skb, &mp_opt); if (subflow->request_mptcp) { if (!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYNACK)) { - if (!mptcp_try_fallback(sk)) + if (!mptcp_try_fallback(sk, + MPTCP_MIB_MPCAPABLEACTIVEFALLBACK)) { + MPTCP_INC_STATS(sock_net(sk), + MPTCP_MIB_FALLBACKFAILED); goto do_reset; + } - MPTCP_INC_STATS(sock_net(sk), - MPTCP_MIB_MPCAPABLEACTIVEFALLBACK); pr_fallback(msk); goto fallback; } @@ -1404,7 +1406,7 @@ fallback: return true; } - if (!mptcp_try_fallback(ssk)) { + if (!mptcp_try_fallback(ssk, MPTCP_MIB_DSSFALLBACK)) { /* fatal protocol error, close the socket. * subflow_error_report() will introduce the appropriate barriers */ --- a/tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c @@ -103,9 +103,9 @@ static int dump_tcp_sock(struct seq_file } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { timer_active = 4; timer_expires = icsk->icsk_timeout; - } else if (timer_pending(&sp->sk_timer)) { + } else if (timer_pending(&icsk->icsk_keepalive_timer)) { timer_active = 2; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; } else { timer_active = 0; timer_expires = bpf_jiffies64(); --- a/tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c +++ b/tools/testing/selftests/bpf/progs/bpf_iter_tcp6.c @@ -103,9 +103,9 @@ static int dump_tcp6_sock(struct seq_fil } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { timer_active = 4; timer_expires = icsk->icsk_timeout; - } else if (timer_pending(&sp->sk_timer)) { + } else if (timer_pending(&icsk->icsk_keepalive_timer)) { timer_active = 2; - timer_expires = sp->sk_timer.expires; + timer_expires = icsk->icsk_keepalive_timer.expires; } else { timer_active = 0; timer_expires = bpf_jiffies64();