diff mbox series

[mptcp-net,1/3] mptcp: fix announced address accounting

Message ID 4a8ac95282ec2b551a64134f24b2e2fd7d82973c.1719589916.git.pabeni@redhat.com (mailing list archive)
State Superseded, archived
Headers show
Series mptcp: fix signal endpoint readd | expand

Checks

Context Check Description
matttbe/build success Build and static analysis OK
matttbe/checkpatch success total: 0 errors, 0 warnings, 0 checks, 58 lines checked
matttbe/shellcheck success MPTCP selftests files have not been modified
matttbe/KVM_Validation__normal success Success! ✅
matttbe/KVM_Validation__debug success Success! ✅
matttbe/KVM_Validation__btf__only_bpftest_all_ success Success! ✅

Commit Message

Paolo Abeni June 28, 2024, 3:54 p.m. UTC
Currently the per connection announced address counter is never
decreased. As a consequence, after connection establishment, if
the NL PM deletes an endpoint and adds a new/different one, no
additional subflow is created for the new endpoint even if the
current limits allow that.

Address the issue properly updating the signaled address counter
every time one of such address is removed.

Fixes: 01cacb00b35c ("mptcp: add netlink-based PM")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
slightly unrelated: is unclear to me why mptcp_pm_remove_addrs() does
things slightly differently from mptcp_pm_remove_addrs_and_subflows(),
with the latter IMHO doing the right thing (TM)
---
 net/mptcp/pm_netlink.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

Comments

Mat Martineau July 1, 2024, 6:08 p.m. UTC | #1
On Fri, 28 Jun 2024, Paolo Abeni wrote:

> Currently the per connection announced address counter is never
> decreased. As a consequence, after connection establishment, if
> the NL PM deletes an endpoint and adds a new/different one, no
> additional subflow is created for the new endpoint even if the
> current limits allow that.
>
> Address the issue properly updating the signaled address counter
> every time one of such address is removed.
>
> Fixes: 01cacb00b35c ("mptcp: add netlink-based PM")
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> ---
> slightly unrelated: is unclear to me why mptcp_pm_remove_addrs() does
> things slightly differently from mptcp_pm_remove_addrs_and_subflows(),
> with the latter IMHO doing the right thing (TM)

Hi Paolo -

I don't remember why mptcp_pm_remove_addrs() has the extra code to send 
the RM_ADDR for addresses that are in the conn_list but not the anno_list. 
Maybe to allow a way to sent RM_ADDR as a "request for the peer to 
initiate a disconnect" even on implicitly added address IDs (from outgoing 
subflow connections instead of ADD_ADDRs)?

> ---
> net/mptcp/pm_netlink.c | 27 +++++++++++++++++++--------
> 1 file changed, 19 insertions(+), 8 deletions(-)
>
> diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
> index ea9e5817b9e9..624f9ea66aea 100644
> --- a/net/mptcp/pm_netlink.c
> +++ b/net/mptcp/pm_netlink.c
> @@ -1401,6 +1401,7 @@ static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk,
> 	ret = remove_anno_list_by_saddr(msk, addr);
> 	if (ret || force) {
> 		spin_lock_bh(&msk->pm.lock);
> +		msk->pm.add_addr_signaled--;

Looks like this only be decremented if ret is true, since that indicates a 
list element was removed and add_addr_signaled is supposed (?) to track 
the length of the anno_list.


- Mat

> 		mptcp_pm_remove_addr(msk, &list);
> 		spin_unlock_bh(&msk->pm.lock);
> 	}
> @@ -1534,16 +1535,25 @@ void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list)
> {
> 	struct mptcp_rm_list alist = { .nr = 0 };
> 	struct mptcp_pm_addr_entry *entry;
> +	int anno_nr = 0;
>
> 	list_for_each_entry(entry, rm_list, list) {
> -		if ((remove_anno_list_by_saddr(msk, &entry->addr) ||
> -		     lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) &&
> -		    alist.nr < MPTCP_RM_IDS_MAX)
> -			alist.ids[alist.nr++] = entry->addr.id;
> +		if (alist.nr >= MPTCP_RM_IDS_MAX)
> +			break;
> +
> +		/* only delete if either announced or matching a subflow */
> +		if (remove_anno_list_by_saddr(msk, &entry->addr))
> +			anno_nr++;
> +		else if (!lookup_subflow_by_saddr(&msk->conn_list,
> +						  &entry->addr))
> +			continue;
> +
> +		alist.ids[alist.nr++] = entry->addr.id;
> 	}
>
> 	if (alist.nr) {
> 		spin_lock_bh(&msk->pm.lock);
> +		msk->pm.add_addr_signaled -= anno_nr;
> 		mptcp_pm_remove_addr(msk, &alist);
> 		spin_unlock_bh(&msk->pm.lock);
> 	}
> @@ -1556,17 +1566,18 @@ static void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
> 	struct mptcp_pm_addr_entry *entry;
>
> 	list_for_each_entry(entry, rm_list, list) {
> -		if (lookup_subflow_by_saddr(&msk->conn_list, &entry->addr) &&
> -		    slist.nr < MPTCP_RM_IDS_MAX)
> +		if (slist.nr < MPTCP_RM_IDS_MAX &&
> +		    lookup_subflow_by_saddr(&msk->conn_list, &entry->addr))
> 			slist.ids[slist.nr++] = entry->addr.id;
>
> -		if (remove_anno_list_by_saddr(msk, &entry->addr) &&
> -		    alist.nr < MPTCP_RM_IDS_MAX)
> +		if (alist.nr < MPTCP_RM_IDS_MAX &&
> +		    remove_anno_list_by_saddr(msk, &entry->addr))
> 			alist.ids[alist.nr++] = entry->addr.id;
> 	}
>
> 	if (alist.nr) {
> 		spin_lock_bh(&msk->pm.lock);
> +		msk->pm.add_addr_signaled -= alist.nr;
> 		mptcp_pm_remove_addr(msk, &alist);
> 		spin_unlock_bh(&msk->pm.lock);
> 	}
> -- 
> 2.45.1
>
>
>
Matthieu Baerts July 2, 2024, 8:51 a.m. UTC | #2
Hi Paolo, Mat,

On 01/07/2024 20:08, Mat Martineau wrote:
> On Fri, 28 Jun 2024, Paolo Abeni wrote:
> 
>> Currently the per connection announced address counter is never
>> decreased. As a consequence, after connection establishment, if
>> the NL PM deletes an endpoint and adds a new/different one, no
>> additional subflow is created for the new endpoint even if the
>> current limits allow that.
>>
>> Address the issue properly updating the signaled address counter
>> every time one of such address is removed.

Thank you for having looked at that!

>> Fixes: 01cacb00b35c ("mptcp: add netlink-based PM")
>> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
>> ---
>> slightly unrelated: is unclear to me why mptcp_pm_remove_addrs() does
>> things slightly differently from mptcp_pm_remove_addrs_and_subflows(),
>> with the latter IMHO doing the right thing (TM)
> 
> Hi Paolo -
> 
> I don't remember why mptcp_pm_remove_addrs() has the extra code to send
> the RM_ADDR for addresses that are in the conn_list but not the
> anno_list. Maybe to allow a way to sent RM_ADDR as a "request for the
> peer to initiate a disconnect" even on implicitly added address IDs
> (from outgoing subflow connections instead of ADD_ADDRs)?

mptcp_pm_remove_addrs() is only used by the userspace PM, it should
probably be moved to pm_userspace.c in fact (but it uses helpers from
pm_netlink.c, I guess that's why it is there). My understanding is that
it also checks the local subflows list because the userspace can ask to
send a remove ADDR for addresses that have been "implicitly" announced
via the MPJoin as well.

Maybe the modification in mptcp_pm_remove_addrs() should be in a
different commit? With a different Fixes tag then:

  Fixes: 8b1c94da1e48 ("mptcp: only send RM_ADDR in nl_cmd_remove")

> 
>> ---
>> net/mptcp/pm_netlink.c | 27 +++++++++++++++++++--------
>> 1 file changed, 19 insertions(+), 8 deletions(-)
>>
>> diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
>> index ea9e5817b9e9..624f9ea66aea 100644
>> --- a/net/mptcp/pm_netlink.c
>> +++ b/net/mptcp/pm_netlink.c
>> @@ -1401,6 +1401,7 @@ static bool mptcp_pm_remove_anno_addr(struct
>> mptcp_sock *msk,
>>     ret = remove_anno_list_by_saddr(msk, addr);
>>     if (ret || force) {
>>         spin_lock_bh(&msk->pm.lock);
>> +        msk->pm.add_addr_signaled--;
> 
> Looks like this only be decremented if ret is true, since that indicates
> a list element was removed and add_addr_signaled is supposed (?) to
> track the length of the anno_list.

Good point.

Should we not also set the corresponding bit in:

  msk->pm.id_avail_signals_bitmap

Linked to my series:


https://lore.kernel.org/mptcp/20240621-mptcp-pm-avail-v1-0-b692d5eb89b5@kernel.org/T/

Otherwise, we will not be able to re-use the same ID, no?

And if we change add_addr_signaled counter here after having removed an
address, maybe now we are no longer at the signalled limit, should we
then call mptcp_pm_create_subflow_or_signal_addr()?

Cheers,
Matt
Matthieu Baerts July 2, 2024, 10:37 a.m. UTC | #3
Hi Paolo,

On 02/07/2024 10:51, Matthieu Baerts wrote:
> Hi Paolo, Mat,
> 
> On 01/07/2024 20:08, Mat Martineau wrote:
>> On Fri, 28 Jun 2024, Paolo Abeni wrote:
>>
>>> Currently the per connection announced address counter is never
>>> decreased. As a consequence, after connection establishment, if
>>> the NL PM deletes an endpoint and adds a new/different one, no
>>> additional subflow is created for the new endpoint even if the
>>> current limits allow that.
>>>
>>> Address the issue properly updating the signaled address counter
>>> every time one of such address is removed.
> 
> Thank you for having looked at that!
> 
>>> Fixes: 01cacb00b35c ("mptcp: add netlink-based PM")
>>> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
>>> ---
>>> slightly unrelated: is unclear to me why mptcp_pm_remove_addrs() does
>>> things slightly differently from mptcp_pm_remove_addrs_and_subflows(),
>>> with the latter IMHO doing the right thing (TM)
>>
>> Hi Paolo -
>>
>> I don't remember why mptcp_pm_remove_addrs() has the extra code to send
>> the RM_ADDR for addresses that are in the conn_list but not the
>> anno_list. Maybe to allow a way to sent RM_ADDR as a "request for the
>> peer to initiate a disconnect" even on implicitly added address IDs
>> (from outgoing subflow connections instead of ADD_ADDRs)?
> 
> mptcp_pm_remove_addrs() is only used by the userspace PM, it should
> probably be moved to pm_userspace.c in fact (but it uses helpers from
> pm_netlink.c, I guess that's why it is there). My understanding is that
> it also checks the local subflows list because the userspace can ask to
> send a remove ADDR for addresses that have been "implicitly" announced
> via the MPJoin as well.
> 
> Maybe the modification in mptcp_pm_remove_addrs() should be in a
> different commit? With a different Fixes tag then:
> 
>   Fixes: 8b1c94da1e48 ("mptcp: only send RM_ADDR in nl_cmd_remove")
> 
>>
>>> ---
>>> net/mptcp/pm_netlink.c | 27 +++++++++++++++++++--------
>>> 1 file changed, 19 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
>>> index ea9e5817b9e9..624f9ea66aea 100644
>>> --- a/net/mptcp/pm_netlink.c
>>> +++ b/net/mptcp/pm_netlink.c
>>> @@ -1401,6 +1401,7 @@ static bool mptcp_pm_remove_anno_addr(struct
>>> mptcp_sock *msk,
>>>     ret = remove_anno_list_by_saddr(msk, addr);
>>>     if (ret || force) {
>>>         spin_lock_bh(&msk->pm.lock);
>>> +        msk->pm.add_addr_signaled--;
>>
>> Looks like this only be decremented if ret is true, since that indicates
>> a list element was removed and add_addr_signaled is supposed (?) to
>> track the length of the anno_list.
> 
> Good point.
> 
> Should we not also set the corresponding bit in:
> 
>   msk->pm.id_avail_signals_bitmap
> 
> Linked to my series:
> 
> 
> https://lore.kernel.org/mptcp/20240621-mptcp-pm-avail-v1-0-b692d5eb89b5@kernel.org/T/
> 
> Otherwise, we will not be able to re-use the same ID, no?

It is a bit confusing, but it looks like the bitmap is modified in some
cases:

- mptcp_pm_remove_anno_addr() is only called from
mptcp_nl_remove_subflow_and_signal_addr(), but for 2 different cases:

  - If there are no additional subflows (list_empty(&msk->conn_list)),
    force == false → the bitmap is not modified

  - If there are additional subflows, and a matching one, force could be
    set to true (if not implicit), but also mptcp_pm_remove_subflow()
    will be called. In this case, the bitmap is modified.

I wonder if it would not be clearer to set the available "signals" bit
in mptcp_pm_remove_addr(), and set the available "subflows" bit in
mptcp_pm_nl_rm_addr_or_subflow(MPTCP_MIB_RMSUBFLOW) -- what the v1 of my
patch is doing [1] -- so one is dedicated to remove endpoints with  the
'signal' flag, and the other one for endpoints with the 'subflow' flag.
WDYT?

[1]
https://lore.kernel.org/r/20240621-mptcp-pm-avail-v1-2-b692d5eb89b5@kernel.org

> And if we change add_addr_signaled counter here after having removed an
> address, maybe now we are no longer at the signalled limit, should we
> then call mptcp_pm_create_subflow_or_signal_addr()?
> 
> Cheers,
> Matt

Cheers,
Matt
Paolo Abeni July 4, 2024, 3:39 p.m. UTC | #4
On Tue, 2024-07-02 at 10:51 +0200, Matthieu Baerts wrote:
> Hi Paolo, Mat,
> 
> On 01/07/2024 20:08, Mat Martineau wrote:
> > On Fri, 28 Jun 2024, Paolo Abeni wrote:
> > 
> > > Currently the per connection announced address counter is never
> > > decreased. As a consequence, after connection establishment, if
> > > the NL PM deletes an endpoint and adds a new/different one, no
> > > additional subflow is created for the new endpoint even if the
> > > current limits allow that.
> > > 
> > > Address the issue properly updating the signaled address counter
> > > every time one of such address is removed.
> 
> Thank you for having looked at that!
> 
> > > Fixes: 01cacb00b35c ("mptcp: add netlink-based PM")
> > > Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> > > ---
> > > slightly unrelated: is unclear to me why mptcp_pm_remove_addrs() does
> > > things slightly differently from mptcp_pm_remove_addrs_and_subflows(),
> > > with the latter IMHO doing the right thing (TM)
> > 
> > Hi Paolo -
> > 
> > I don't remember why mptcp_pm_remove_addrs() has the extra code to send
> > the RM_ADDR for addresses that are in the conn_list but not the
> > anno_list. Maybe to allow a way to sent RM_ADDR as a "request for the
> > peer to initiate a disconnect" even on implicitly added address IDs
> > (from outgoing subflow connections instead of ADD_ADDRs)?
> 
> mptcp_pm_remove_addrs() is only used by the userspace PM, it should
> probably be moved to pm_userspace.c in fact (but it uses helpers from
> pm_netlink.c, I guess that's why it is there). My understanding is that
> it also checks the local subflows list because the userspace can ask to
> send a remove ADDR for addresses that have been "implicitly" announced
> via the MPJoin as well.
> 
> Maybe the modification in mptcp_pm_remove_addrs() should be in a
> different commit? With a different Fixes tag then:
> 
>   Fixes: 8b1c94da1e48 ("mptcp: only send RM_ADDR in nl_cmd_remove")
> 
> > 
> > > ---
> > > net/mptcp/pm_netlink.c | 27 +++++++++++++++++++--------
> > > 1 file changed, 19 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
> > > index ea9e5817b9e9..624f9ea66aea 100644
> > > --- a/net/mptcp/pm_netlink.c
> > > +++ b/net/mptcp/pm_netlink.c
> > > @@ -1401,6 +1401,7 @@ static bool mptcp_pm_remove_anno_addr(struct
> > > mptcp_sock *msk,
> > >     ret = remove_anno_list_by_saddr(msk, addr);
> > >     if (ret || force) {
> > >         spin_lock_bh(&msk->pm.lock);
> > > +        msk->pm.add_addr_signaled--;
> > 
> > Looks like this only be decremented if ret is true, since that indicates
> > a list element was removed and add_addr_signaled is supposed (?) to
> > track the length of the anno_list.
> 
> Good point.
> 
> Should we not also set the corresponding bit in:
> 
>   msk->pm.id_avail_signals_bitmap
> 
> Linked to my series:
> 
> 
> https://lore.kernel.org/mptcp/20240621-mptcp-pm-avail-v1-0-b692d5eb89b5@kernel.org/T/
> 
> Otherwise, we will not be able to re-use the same ID, no?

This is for net, your series is rightfully for net-next, I guess you
should do the id_avail_signals_bitmap accounting only on the latter.

Thanks,

Paolo
diff mbox series

Patch

diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index ea9e5817b9e9..624f9ea66aea 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -1401,6 +1401,7 @@  static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk,
 	ret = remove_anno_list_by_saddr(msk, addr);
 	if (ret || force) {
 		spin_lock_bh(&msk->pm.lock);
+		msk->pm.add_addr_signaled--;
 		mptcp_pm_remove_addr(msk, &list);
 		spin_unlock_bh(&msk->pm.lock);
 	}
@@ -1534,16 +1535,25 @@  void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list)
 {
 	struct mptcp_rm_list alist = { .nr = 0 };
 	struct mptcp_pm_addr_entry *entry;
+	int anno_nr = 0;
 
 	list_for_each_entry(entry, rm_list, list) {
-		if ((remove_anno_list_by_saddr(msk, &entry->addr) ||
-		     lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) &&
-		    alist.nr < MPTCP_RM_IDS_MAX)
-			alist.ids[alist.nr++] = entry->addr.id;
+		if (alist.nr >= MPTCP_RM_IDS_MAX)
+			break;
+
+		/* only delete if either announced or matching a subflow */
+		if (remove_anno_list_by_saddr(msk, &entry->addr))
+			anno_nr++;
+		else if (!lookup_subflow_by_saddr(&msk->conn_list,
+						  &entry->addr))
+			continue;
+
+		alist.ids[alist.nr++] = entry->addr.id;
 	}
 
 	if (alist.nr) {
 		spin_lock_bh(&msk->pm.lock);
+		msk->pm.add_addr_signaled -= anno_nr;
 		mptcp_pm_remove_addr(msk, &alist);
 		spin_unlock_bh(&msk->pm.lock);
 	}
@@ -1556,17 +1566,18 @@  static void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
 	struct mptcp_pm_addr_entry *entry;
 
 	list_for_each_entry(entry, rm_list, list) {
-		if (lookup_subflow_by_saddr(&msk->conn_list, &entry->addr) &&
-		    slist.nr < MPTCP_RM_IDS_MAX)
+		if (slist.nr < MPTCP_RM_IDS_MAX &&
+		    lookup_subflow_by_saddr(&msk->conn_list, &entry->addr))
 			slist.ids[slist.nr++] = entry->addr.id;
 
-		if (remove_anno_list_by_saddr(msk, &entry->addr) &&
-		    alist.nr < MPTCP_RM_IDS_MAX)
+		if (alist.nr < MPTCP_RM_IDS_MAX &&
+		    remove_anno_list_by_saddr(msk, &entry->addr))
 			alist.ids[alist.nr++] = entry->addr.id;
 	}
 
 	if (alist.nr) {
 		spin_lock_bh(&msk->pm.lock);
+		msk->pm.add_addr_signaled -= alist.nr;
 		mptcp_pm_remove_addr(msk, &alist);
 		spin_unlock_bh(&msk->pm.lock);
 	}