[PATCH mptcp-net v2 3/3] mptcp: add MPFailFallback MIB for MP_FAIL TCP fallback

Chenguang Zhao <[email protected]> Wed, 15 Jul 2026 14:18:30 +0800
Newsgroups dev.linux.lists.mptcp
Message-ID <[email protected]>
From: Chenguang Zhao <[email protected]>

Track fallbacks triggered by receiving MP_FAIL with a dedicated MIB, and
switch mptcp_pm_mp_fail_received() to mptcp_try_fallback() so the counter
is updated and pending DATA_FIN is handled through the common path.
InfiniteMapTx remains counted when the infinite mapping is transmitted.

Signed-off-by: Chenguang Zhao <[email protected]>
---
 net/mptcp/mib.c |  1 +
 net/mptcp/mib.h |  1 +
 net/mptcp/pm.c  | 28 ++++------------------------
 3 files changed, 6 insertions(+), 24 deletions(-)

diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c
index f23fda0c55a7..4dc107ab1aec 100644
--- a/net/mptcp/mib.c
+++ b/net/mptcp/mib.c
@@ -83,6 +83,7 @@ static const struct snmp_mib mptcp_snmp_list[] = {
 	SNMP_MIB_ITEM("MD5SigFallback", MPTCP_MIB_MD5SIGFALLBACK),
 	SNMP_MIB_ITEM("DssFallback", MPTCP_MIB_DSSFALLBACK),
 	SNMP_MIB_ITEM("SimultConnectFallback", MPTCP_MIB_SIMULTCONNFALLBACK),
+	SNMP_MIB_ITEM("MPFailFallback", MPTCP_MIB_MPFAILFALLBACK),
 	SNMP_MIB_ITEM("FallbackFailed", MPTCP_MIB_FALLBACKFAILED),
 	SNMP_MIB_ITEM("WinProbe", MPTCP_MIB_WINPROBE),
 };
diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h
index 812218b5ed2b..9db8812d8e04 100644
--- a/net/mptcp/mib.h
+++ b/net/mptcp/mib.h
@@ -86,6 +86,7 @@ enum linux_mptcp_mib_field {
 	MPTCP_MIB_MD5SIGFALLBACK,	/* Conflicting TCP option enabled */
 	MPTCP_MIB_DSSFALLBACK,		/* Bad or missing DSS */
 	MPTCP_MIB_SIMULTCONNFALLBACK,	/* Simultaneous connect */
+	MPTCP_MIB_MPFAILFALLBACK,	/* Received MP_FAIL, fallback to TCP */
 	MPTCP_MIB_FALLBACKFAILED,	/* Can't fallback due to msk status */
 	MPTCP_MIB_WINPROBE,		/* MPTCP-level zero window probe */
 	__MPTCP_MIB_MAX
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 869876a06493..82d3dbedd603 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -906,33 +906,13 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 		tcp_send_ack(sk);
 
 		/* RFC8684 ยง3.7: after accepting MP_FAIL with a single
-		 * subflow, leave MPTCP mode and never revert. No dedicated
-		 * fallback MIB yet; InfiniteMapTx is counted when the map
-		 * is transmitted. Handle pending DATA_FIN like
-		 * mptcp_try_fallback().
+		 * subflow, leave MPTCP mode and never revert. Use
+		 * mptcp_try_fallback() so pending DATA_FIN is handled.
+		 * InfiniteMapTx is counted when the map is transmitted.
 		 */
-		spin_lock_bh(&msk->fallback_lock);
-		if (__mptcp_check_fallback(msk)) {
-			spin_unlock_bh(&msk->fallback_lock);
-			return;
-		}
-		if (!msk->allow_infinite_fallback) {
-			spin_unlock_bh(&msk->fallback_lock);
+		if (!mptcp_try_fallback(sk, MPTCP_MIB_MPFAILFALLBACK)) {
 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FALLBACKFAILED);
 			mptcp_subflow_reset(sk);
-			return;
-		}
-		set_bit(MPTCP_FALLBACK_DONE, &msk->flags);
-		spin_unlock_bh(&msk->fallback_lock);
-
-		if (READ_ONCE(msk->snd_data_fin_enable) &&
-		    !(sk->sk_shutdown & SEND_SHUTDOWN)) {
-			gfp_t saved_allocation = sk->sk_allocation;
-
-			sk->sk_allocation = GFP_ATOMIC;
-			sk->sk_shutdown |= SEND_SHUTDOWN;
-			tcp_shutdown(sk, SEND_SHUTDOWN);
-			sk->sk_allocation = saved_allocation;
 		}
 	} else {
 		pr_debug("MP_FAIL response received\n");
-- 
2.25.1