From nobody Sat Aug 15 20:32:02 2026 Received: from sender4-of-o54.zoho.com (sender4-of-o54.zoho.com [136.143.188.54]) (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 9C50E468C37 for ; Thu, 13 Aug 2026 12:38:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.54 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786624708; cv=pass; b=a2f9jN9WlesxVKBypS6htkdmCUCu85Sqnaiwaru7iiB1wDErR8bf0ye+9WCaOIch5AyA9DwBSE4mx43NUcg5yzh6U6jbbpdH9o23V3oc42O1GYTW6au36RT0jtroHIX0HphDEkaKdyjEUeIi4vXxwAz+Y/fUpHjcVIE1Aebkn8Y= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786624708; c=relaxed/simple; bh=FzPAY8prNT2U6v/OgbIV7qJ/vODyqFmXh3GFY4Pz2FQ=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=SXFefebnZaxcj2gWHvGt8p1drU4St5R9mOmetvlhUNbsE/PBwEBjvvtxamymQCAaGU7rLaivwZtZGFiec14wtAcoKGfqCrpCKTODj5zWGu+cPKm3apchX6PlFItFqXdZNP2HSqtn0cu76a+POjh+LTPdIo6erMjsWRBJzdIbyd4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mpiricsoftware.com; spf=pass smtp.mailfrom=mpiricsoftware.com; dkim=fail (0-bit key) header.d=mpiricsoftware.com header.i=akshit@mpiricsoftware.com header.b=e6V5NQ0L reason="key not found in DNS"; arc=pass smtp.client-ip=136.143.188.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=mpiricsoftware.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mpiricsoftware.com Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=mpiricsoftware.com header.i=akshit@mpiricsoftware.com header.b="e6V5NQ0L" ARC-Seal: i=1; a=rsa-sha256; t=1786624693; cv=none; d=zohomail.com; s=zohoarc; b=V03GeTS6mssxWshIK5mM0PEWWYX87+Y4aiwmQASaHcTwC2GWikvULKiZrSs0aj8nlMMxhZjE+kk8O3nLiavKA2KbElHuV8N4gVlKecOFR0SagrvBhgITJhez8l3z2l4q9MvHFKx0/9e+cm7Srx3nm0YPNf5qqL6Bq7VEctI0JwQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786624693; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:MIME-Version:Message-ID:Subject:Subject:To:To:Message-Id:Reply-To; bh=fjj7ppDWuxiMWR9c8WAkuAAGGKrZHqZVeLpptfZXKjo=; b=MpRP4KW/AZxR7ChDZyEiyNe0jPKC7qZmGHz8YNi5nsLN6oQPpFDHiuNraENm4W/Aj4jjXb3U34AOoVN2G6FLqNJIwH9dR15w/PW3aThlSjrDHQa/nkd9LkOrNu5egpxuSgysbaNAfqE+KCNSO2nOTf8rvDXZ6K0grJ5s3VpCQ3k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=mpiricsoftware.com; spf=pass smtp.mailfrom=akshit@mpiricsoftware.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1786624693; s=mpiric; d=mpiricsoftware.com; i=akshit@mpiricsoftware.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-ID:MIME-Version:Content-Transfer-Encoding:Message-Id:Reply-To; bh=fjj7ppDWuxiMWR9c8WAkuAAGGKrZHqZVeLpptfZXKjo=; b=e6V5NQ0LtJ7sZ7mPnb8u+t60+LovETO4bfK85DDFBaoHd+i8R8erIX/SjpCpim9L AGbb999b80KuB0ZsrMdCuCwECOo8R/s23AWZL+Q6PEz4S1IWPcrdckL15rcyCrqZ1fv Y8sqFwRKeMXf6SgunmJ7ZAfQQS2pzc2Iy2jhvC6Y= Received: by mx.zohomail.com with SMTPS id 1786624686199665.3126228216203; Thu, 13 Aug 2026 05:38:06 -0700 (PDT) From: Akshit Patadiya To: mptcp@lists.linux.dev Cc: matttbe@kernel.org, martineau@kernel.org, pabeni@redhat.com, shardul.b@mpiricsoftware.com, janak@mpiric.us, kalpanjani009@gmail.com, kalpan.jani@mpiricsoftware.com, akshit@mpiric.us, Akshit Patadiya Subject: [PATCH mptcp-next] mptcp: fix add_addr_accepted accounting on subflow close Date: Thu, 13 Aug 2026 18:07:54 +0530 Message-ID: <20260813123754.4095492-1-akshit@mpiricsoftware.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMailClient: External Content-Type: text/plain; charset="utf-8" When an accepted remote address is used by a subflow that is closed before the corresponding RM_ADDR is received, the add_addr_accepted counter is not decremented when the subflow is removed. As a result, the accepted-address budget can remain consumed for the lifetime of the MPTCP connection. A subsequent ADD_ADDR is then not acted upon because the peer is considered to have already reached the add_addr_accepted limit. Track accepted remote address IDs in a bitmap instead of relying on a live subflow to signal removal. Release the accepted-address slot as soon as the subflow using it is closed, instead of depending on a matching RM_ADDR that may never arrive. The same bitmap also guards against double-counting if the same address ID is accepted more than once. This allows a new MP_JOIN to be created after a previously accepted subflow has been closed and its address has been removed. Fixes: 1c1f72137598 ("mptcp: pm: only decrement add_addr_accepted for MPJ r= eq") Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/498 Signed-off-by: Akshit Patadiya --- net/mptcp/pm.c | 8 +++--- net/mptcp/pm_kernel.c | 63 ++++++++++++++++++++++++++++++++++++------- net/mptcp/protocol.h | 3 +++ 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index ba7c6f80a183..b6edb9df3216 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -681,8 +681,10 @@ void mptcp_pm_subflow_check_next(struct mptcp_sock *ms= k, return; =20 spin_lock_bh(&pm->lock); - if (update_subflows) + if (update_subflows) { __mptcp_pm_close_subflow(msk); + mptcp_pm_nl_close_subflow(msk, subflow); + } =20 /* Even if this subflow is not really established, tell the PM to try * to pick the next ones, if possible. @@ -786,7 +788,6 @@ static void mptcp_pm_rm_addr_or_subflow(struct mptcp_so= ck *msk, =20 for (i =3D 0; i < rm_list->nr; i++) { u8 rm_id =3D rm_list->ids[i]; - bool removed =3D false; =20 mptcp_for_each_subflow_safe(msk, subflow, tmp) { struct sock *ssk =3D mptcp_subflow_tcp_sock(subflow); @@ -807,7 +808,6 @@ static void mptcp_pm_rm_addr_or_subflow(struct mptcp_so= ck *msk, i, rm_id, id, remote_id, msk->mpc_endpoint_id); spin_unlock_bh(&msk->pm.lock); mptcp_subflow_shutdown(sk, ssk, how); - removed |=3D subflow->request_join; =20 /* the following takes care of updating the subflows counter */ mptcp_close_ssk(sk, ssk, subflow); @@ -819,7 +819,7 @@ static void mptcp_pm_rm_addr_or_subflow(struct mptcp_so= ck *msk, =20 if (rm_type =3D=3D MPTCP_MIB_RMADDR) { __MPTCP_INC_STATS(sock_net(sk), rm_type); - if (removed && mptcp_pm_is_kernel(msk)) + if (mptcp_pm_is_kernel(msk)) mptcp_pm_nl_rm_addr(msk, rm_id); } } diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index d3014bf57bf3..8b087677a4e7 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -694,8 +694,13 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp= _sock *msk) spin_lock_bh(&msk->pm.lock); =20 if (sf_created) { - /* add_addr_accepted is not decr for ID 0 */ - if (remote.id) + /* ID 0 is not accounted: the remote address of the initial + * subflow is known from the beginning. Remember the other + * accepted IDs, so the counter can be balanced later on even + * if the linked subflows are gone by then. + */ + if (remote.id && + !__test_and_set_bit(remote.id, msk->pm.id_accepted_bitmap)) msk->pm.add_addr_accepted++; if (msk->pm.add_addr_accepted >=3D limit_add_addr_accepted || msk->pm.extra_subflows >=3D limit_extra_subflows) @@ -705,16 +710,53 @@ static void mptcp_pm_nl_add_addr_received(struct mptc= p_sock *msk) =20 void mptcp_pm_nl_rm_addr(struct mptcp_sock *msk, u8 rm_id) { - if (rm_id && !WARN_ON_ONCE(msk->pm.add_addr_accepted =3D=3D 0)) { - u8 limit_add_addr_accepted =3D - mptcp_pm_get_limit_add_addr_accepted(msk); + u8 limit_add_addr_accepted; =20 - /* Note: if the subflow has been closed before, this - * add_addr_accepted counter will not be decremented. - */ - if (--msk->pm.add_addr_accepted < limit_add_addr_accepted) - WRITE_ONCE(msk->pm.accept_addr, true); + /* Only remote addresses that have been accepted by this host are + * accounted: not ID 0, and not MP_JOIN requests initiated by the peer. + * The bit, not the presence of a subflow, is what tells them apart, so + * this works even when the subflows are already closed, and a + * duplicated RM_ADDR is a no-op. + */ + if (!rm_id || !__test_and_clear_bit(rm_id, msk->pm.id_accepted_bitmap)) + return; + + if (WARN_ON_ONCE(msk->pm.add_addr_accepted =3D=3D 0)) + return; + + limit_add_addr_accepted =3D mptcp_pm_get_limit_add_addr_accepted(msk); + if (--msk->pm.add_addr_accepted < limit_add_addr_accepted) + WRITE_ONCE(msk->pm.accept_addr, true); +} + +/* Called with the PM lock held, from the subflow close path, before the + * subflow is removed from conn_list. + */ +void mptcp_pm_nl_close_subflow(struct mptcp_sock *msk, + const struct mptcp_subflow_context *subflow) +{ + u8 remote_id =3D READ_ONCE(subflow->remote_id); + struct mptcp_subflow_context *iter; + + /* Only the subflows this host has created upon an ADD_ADDR reception + * are accounted, and never the initial one. + */ + if (!subflow->request_join || !remote_id || + !test_bit(remote_id, msk->pm.id_accepted_bitmap)) + return; + + /* The remote address can still be used by another subflow, e.g. with + * fullmesh endpoints. + */ + mptcp_for_each_subflow(msk, iter) { + if (iter =3D=3D subflow || iter->close_event_done) + continue; + if (iter->request_join && + READ_ONCE(iter->remote_id) =3D=3D remote_id) + return; } + + mptcp_pm_nl_rm_addr(msk, remote_id); } =20 static bool address_use_port(struct mptcp_pm_addr_entry *entry) @@ -1668,6 +1710,7 @@ static void mptcp_pm_kernel_init(struct mptcp_sock *m= sk) WRITE_ONCE(pm->accept_subflow, subflows_allowed); =20 bitmap_fill(pm->id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); + bitmap_zero(pm->id_accepted_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); } =20 struct mptcp_pm_ops mptcp_pm_kernel =3D { diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 7e168e450fb0..54663d7aca34 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -243,6 +243,7 @@ struct mptcp_pm_data { ); =20 DECLARE_BITMAP(id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); + DECLARE_BITMAP(id_accepted_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); struct mptcp_rm_list rm_list_tx; struct mptcp_rm_list rm_list_rx; }; @@ -1127,6 +1128,8 @@ void mptcp_pm_send_ack(struct mptcp_sock *msk, bool prio, bool backup); void mptcp_pm_addr_send_ack(struct mptcp_sock *msk); void mptcp_pm_nl_rm_addr(struct mptcp_sock *msk, u8 rm_id); +void mptcp_pm_nl_close_subflow(struct mptcp_sock *msk, + const struct mptcp_subflow_context *subflow); void mptcp_pm_rm_subflow(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list); void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, --=20 2.43.0