diff mbox series

[v4,mptcp-next,5/5] mptcp: add remove subflow support

Message ID ed14dde1c2b56f772f7f4ecda9d30b5411fa6563.1596106606.git.geliangtang@gmail.com
State Superseded, archived
Headers show
Series Add REMOVE_ADDR support | expand

Commit Message

Geliang Tang July 30, 2020, 11:06 a.m. UTC
This patch added a new function mptcp_nl_remove_subflow to handle the
'MPTCP_PM_ADDR_FLAG_SUBFLOW' flag case. Do the local subflow removing
in this function.

Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
 net/mptcp/pm_netlink.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

Comments

Paolo Abeni July 30, 2020, 8:39 p.m. UTC | #1
On Thu, 2020-07-30 at 19:06 +0800, Geliang Tang wrote:
> This patch added a new function mptcp_nl_remove_subflow to handle the
> 'MPTCP_PM_ADDR_FLAG_SUBFLOW' flag case. Do the local subflow removing
> in this function.
> 
> Signed-off-by: Geliang Tang <geliangtang@gmail.com>
> ---
>  net/mptcp/pm_netlink.c | 30 ++++++++++++++++++++++++++++--
>  1 file changed, 28 insertions(+), 2 deletions(-)
> 
> diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
> index b9f0622e4082..e1fcd0ff0624 100644
> --- a/net/mptcp/pm_netlink.c
> +++ b/net/mptcp/pm_netlink.c
> @@ -304,7 +304,8 @@ void mptcp_pm_nl_rm_addr_received(struct mptcp_sock *msk)
>  		int how = RCV_SHUTDOWN | SEND_SHUTDOWN;
>  		long timeout = 0;
>  
> -		if (msk->pm.rm_id == subflow->remote_id) {
> +		if (msk->pm.rm_id == subflow->remote_id ||
> +		    msk->pm.rm_id == subflow->local_id) {
>  			spin_unlock_bh(&msk->pm.lock);
>  			mptcp_subflow_shutdown(sk, ssk, how);
>  			__mptcp_close_ssk(sk, ssk, subflow, timeout);
> @@ -593,6 +594,29 @@ static void mptcp_nl_remove_addr(struct sk_buff *skb, struct mptcp_addr_info *ad
>  	}
>  }
>  
> +static void mptcp_nl_remove_subflow(struct sk_buff *skb, struct mptcp_addr_info *addr)
> +{
> +	struct mptcp_sock *msk;
> +	long s_slot = 0, s_num = 0;
> +	struct net *net = sock_net(skb->sk);
> +
> +	while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
> +		struct mptcp_subflow_context *subflow, *tmp;
> +		struct sock *sk = (struct sock *)msk;
> +
> +		pr_debug("msk=%p\n", msk);
> +		list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {

To safely traverse the msk->conn_list you must acquire the msk socket
lock first.

> +			struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
> +			struct mptcp_addr_info local;
> +
> +			local_address((struct sock_common *)ssk, &local);
> +			if (addresses_equal(&local, addr, false))
> +				mptcp_pm_rm_addr_received(msk, addr->id);

mptcp_pm_rm_addr_received() assumes the msk pm lock is held, so you
must acquire it before the call and release after.

> +		}
> +		sock_put(sk);

Here another:
		cond_resched();

could help.

> +	}
> +}
> +
>  static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
>  {
>  	struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
> @@ -615,8 +639,10 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
>  		pernet->add_addr_signal_max--;
>  		mptcp_nl_remove_addr(skb, &entry->addr);
>  	}
> -	if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)
> +	if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
>  		pernet->local_addr_max--;
> +		mptcp_nl_remove_subflow(skb, &entry->addr);

whoops, I did not notice before here we are in atomic context (under
pernet->lock)

So we can't reschedule - as needed - nor acquire the socket lock.

I think some code reordering is needed:


	//...
	if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SIGNAL)
                pernet->add_addr_signal_max--;
        if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)
                pernet->local_addr_max--;
	pernet->addrs--;
        list_del_rcu(&entry->list);
	spin_unlock_bh(&pernet->lock);

	if (entry->addr.flags &	MPTCP_PM_ADDR_FLAG_SUBFLOW)
		mptcp_nl_remove_subflow()
	kfree_rcu(entry, rcu);

And a similar handling for mptcp_pm_nl_rm_addr_received()
	
> +	}
>  
>  	pernet->addrs--;
>  	list_del_rcu(&entry->list);
diff mbox series

Patch

diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index b9f0622e4082..e1fcd0ff0624 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -304,7 +304,8 @@  void mptcp_pm_nl_rm_addr_received(struct mptcp_sock *msk)
 		int how = RCV_SHUTDOWN | SEND_SHUTDOWN;
 		long timeout = 0;
 
-		if (msk->pm.rm_id == subflow->remote_id) {
+		if (msk->pm.rm_id == subflow->remote_id ||
+		    msk->pm.rm_id == subflow->local_id) {
 			spin_unlock_bh(&msk->pm.lock);
 			mptcp_subflow_shutdown(sk, ssk, how);
 			__mptcp_close_ssk(sk, ssk, subflow, timeout);
@@ -593,6 +594,29 @@  static void mptcp_nl_remove_addr(struct sk_buff *skb, struct mptcp_addr_info *ad
 	}
 }
 
+static void mptcp_nl_remove_subflow(struct sk_buff *skb, struct mptcp_addr_info *addr)
+{
+	struct mptcp_sock *msk;
+	long s_slot = 0, s_num = 0;
+	struct net *net = sock_net(skb->sk);
+
+	while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
+		struct mptcp_subflow_context *subflow, *tmp;
+		struct sock *sk = (struct sock *)msk;
+
+		pr_debug("msk=%p\n", msk);
+		list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
+			struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+			struct mptcp_addr_info local;
+
+			local_address((struct sock_common *)ssk, &local);
+			if (addresses_equal(&local, addr, false))
+				mptcp_pm_rm_addr_received(msk, addr->id);
+		}
+		sock_put(sk);
+	}
+}
+
 static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
@@ -615,8 +639,10 @@  static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
 		pernet->add_addr_signal_max--;
 		mptcp_nl_remove_addr(skb, &entry->addr);
 	}
-	if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)
+	if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
 		pernet->local_addr_max--;
+		mptcp_nl_remove_subflow(skb, &entry->addr);
+	}
 
 	pernet->addrs--;
 	list_del_rcu(&entry->list);