diff mbox series

[v5,mptcp-next,3/3] mptcp: retransmit ADD_ADDR when timeout

Message ID 201c99be5aeb750b74a9b2710a5674dc700e6c48.1600672866.git.geliangtang@gmail.com
State Accepted, archived
Delegated to: Matthieu Baerts
Headers show
Series mptcp: retransmit ADD_ADDR when timeout and others | expand

Commit Message

Geliang Tang Sept. 21, 2020, 7:30 a.m. UTC
This patch implemented the retransmition of ADD_ADDR when no ADD_ADDR echo
is received. It added a timer with the announced address. When timeout
occurs, ADD_ADDR will be retransmitted.

Suggested-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
 net/mptcp/options.c    |   1 +
 net/mptcp/pm_netlink.c | 113 ++++++++++++++++++++++++++++++++++-------
 net/mptcp/protocol.h   |   3 ++
 3 files changed, 98 insertions(+), 19 deletions(-)

Comments

Paolo Abeni Sept. 21, 2020, 10:24 a.m. UTC | #1
Hi,

Thank you for the prompt turn-over. There is still a somewhat relevant
item - the last comment in this patch. The others comments are mostly
nit picking, but nice to have.

On Mon, 2020-09-21 at 15:30 +0800, Geliang Tang wrote:
> This patch implemented the retransmition of ADD_ADDR when no ADD_ADDR
> echo
> is received. It added a timer with the announced address. When
> timeout
> occurs, ADD_ADDR will be retransmitted.
> 
> Suggested-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
> Suggested-by: Paolo Abeni <pabeni@redhat.com>
> Signed-off-by: Geliang Tang <geliangtang@gmail.com>
> ---
>  net/mptcp/options.c    |   1 +
>  net/mptcp/pm_netlink.c | 113 ++++++++++++++++++++++++++++++++++-----
> --
>  net/mptcp/protocol.h   |   3 ++
>  3 files changed, 98 insertions(+), 19 deletions(-)
> 
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index 171039cbe9c4..14a290fae767 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -893,6 +893,7 @@ void mptcp_incoming_options(struct sock *sk,
> struct sk_buff *skb,
>  			mptcp_pm_add_addr_received(msk, &addr);
>  			MPTCP_INC_STATS(sock_net(sk),
> MPTCP_MIB_ADDADDR);
>  		} else {
> +			mptcp_pm_del_add_timer(msk, &addr);
>  			MPTCP_INC_STATS(sock_net(sk),
> MPTCP_MIB_ECHOADD);
>  		}
>  		mp_opt.add_addr = 0;
> diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
> index 701972b55a45..6fad2cc4cf5d 100644
> --- a/net/mptcp/pm_netlink.c
> +++ b/net/mptcp/pm_netlink.c
> @@ -31,6 +31,9 @@ struct mptcp_pm_addr_entry {
>  struct mptcp_pm_add_entry {
>  	struct list_head	list;
>  	struct mptcp_addr_info	addr;
> +	struct timer_list	add_timer;
> +	struct mptcp_sock	*sock;
> +	u8			retrans_times;
>  };
>  
>  struct pm_nl_pernet {
> @@ -46,6 +49,7 @@ struct pm_nl_pernet {
>  };
>  
>  #define MPTCP_PM_ADDR_MAX	8
> +#define ADD_ADDR_RETRANS_MAX	3
>  
>  static bool addresses_equal(const struct mptcp_addr_info *a,
>  			    struct mptcp_addr_info *b, bool use_port)
> @@ -183,23 +187,83 @@ static void check_work_pending(struct
> mptcp_sock *msk)
>  		WRITE_ONCE(msk->pm.work_pending, false);
>  }
>  
> -static bool lookup_anno_list_by_saddr(struct mptcp_sock *msk,
> -				      struct mptcp_addr_info *addr)
> +static struct mptcp_pm_add_entry *
> +lookup_anno_list_by_saddr(struct mptcp_sock *msk,
> +			  struct mptcp_addr_info *addr)
>  {
> -	struct mptcp_pm_add_entry *entry;
> +	struct mptcp_pm_add_entry *entry, *ret = NULL;
>  
>  	list_for_each_entry(entry, &msk->pm.anno_list, list) {
> -		if (addresses_equal(&entry->addr, addr, false))
> -			return true;
> +		if (addresses_equal(&entry->addr, addr, false)) {
> +			ret = entry;
> +			break;

Or simply:
			return entry;

No braches, no break, no local variable.
> +		}
>  	}
>  
> -	return false;
> +	return ret;

[with the above change]
	return NULL;
> +}
> +
> +static void mptcp_pm_add_timer(struct timer_list *timer)
> +{
> +	struct mptcp_pm_add_entry *entry = from_timer(entry, timer,
> add_timer);
> +	struct mptcp_sock *msk = entry->sock;
> +	struct sock *sk = (struct sock *)msk;
> +
> +	pr_debug("msk=%p", msk);
> +
> +	if (!msk)
> +		return;
> +
> +	if (sk->sk_state == TCP_CLOSE)

Since this is a lockless context (sorry for not noticing it before):

	if (inet_sk_state_load(sk))

> +		return;
> +
> +	if (!entry->addr.id)
> +		return;
> +
> +	if (mptcp_pm_should_add_signal(msk)) {
> +		sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8);
> +		goto out;
> +	}
> +
> +	spin_lock_bh(&msk->pm.lock);
> +
> +	if (!mptcp_pm_should_add_signal(msk)) {
> +		pr_debug("retransmit ADD_ADDR id=%d", entry->addr.id);
> +		mptcp_pm_announce_addr(msk, &entry->addr, false);
> +		entry->retrans_times++;
> +	}
> +
> +	if (entry->retrans_times < ADD_ADDR_RETRANS_MAX)
> +		sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX);
> +
> +	spin_unlock_bh(&msk->pm.lock);
> +
> +out:
> +	__sock_put(sk);
> +}
> +
> +struct mptcp_pm_add_entry *
> +mptcp_pm_del_add_timer(struct mptcp_sock *msk,
> +		       struct mptcp_addr_info *addr)
> +{
> +	struct mptcp_pm_add_entry *entry;
> +	struct sock *sk = (struct sock *)msk;
> +
> +	spin_lock_bh(&msk->pm.lock);
> +	entry = lookup_anno_list_by_saddr(msk, addr);

here it's additionally needed:

	entry->retrans_times = ADD_ADDR_RETRANS_MAX;

to prevent the timer re-scheduling, or bad things could happen!


Cheers,

Paolo
Matthieu Baerts Sept. 21, 2020, 5:53 p.m. UTC | #2
Hi Geliang, Paolo

On 21/09/2020 12:24, Paolo Abeni wrote:
> Hi,
> 
> Thank you for the prompt turn-over. There is still a somewhat relevant
> item - the last comment in this patch. The others comments are mostly
> nit picking, but nice to have.
> 
> On Mon, 2020-09-21 at 15:30 +0800, Geliang Tang wrote:
>> This patch implemented the retransmition of ADD_ADDR when no ADD_ADDR
>> echo
>> is received. It added a timer with the announced address. When
>> timeout
>> occurs, ADD_ADDR will be retransmitted.
>>
>> Suggested-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
>> Suggested-by: Paolo Abeni <pabeni@redhat.com>
>> Signed-off-by: Geliang Tang <geliangtang@gmail.com>

As discussed on IRC, I just applied this patch + the "squash to" one:

- a972ed5d1ec5: mptcp: add struct mptcp_pm_add_entry
- 39a25e21cbca: mptcp: add sk_stop_timer_sync helper
- e83b080276ea: mptcp: retransmit ADD_ADDR when timeout

Paolo's ACK has been added to these three patches. I applied these 
patches after Geliang' selftests patches because the timeout feature is 
not validated by any kselftests.

- fe8df13fc5d3..8c5acf4c1ab3: result

Note that it would maybe be more interesting to add packetdrill test to 
validate this feature.

Tests + export are going to be started soon.

Cheers,
Matt
Geliang Tang Sept. 22, 2020, 2:29 a.m. UTC | #3
Hi Matt,

Matthieu Baerts <matthieu.baerts@tessares.net> 于2020年9月22日周二 上午1:53写道:
>
> Hi Geliang, Paolo
>
> On 21/09/2020 12:24, Paolo Abeni wrote:
> > Hi,
> >
> > Thank you for the prompt turn-over. There is still a somewhat relevant
> > item - the last comment in this patch. The others comments are mostly
> > nit picking, but nice to have.
> >
> > On Mon, 2020-09-21 at 15:30 +0800, Geliang Tang wrote:
> >> This patch implemented the retransmition of ADD_ADDR when no ADD_ADDR
> >> echo
> >> is received. It added a timer with the announced address. When
> >> timeout
> >> occurs, ADD_ADDR will be retransmitted.
> >>
> >> Suggested-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
> >> Suggested-by: Paolo Abeni <pabeni@redhat.com>
> >> Signed-off-by: Geliang Tang <geliangtang@gmail.com>
>
> As discussed on IRC, I just applied this patch + the "squash to" one:
>
> - a972ed5d1ec5: mptcp: add struct mptcp_pm_add_entry
> - 39a25e21cbca: mptcp: add sk_stop_timer_sync helper
> - e83b080276ea: mptcp: retransmit ADD_ADDR when timeout
>
> Paolo's ACK has been added to these three patches. I applied these
> patches after Geliang' selftests patches because the timeout feature is
> not validated by any kselftests.

Thanks, as these patches have been applied, I think both issue #49 (ADD_ADDR:
echo bit support) and issue #50 (REMOVE_ADDR support) could be closed.

And I'll write the selftest case of these patches later.

-Geliang

>
> - fe8df13fc5d3..8c5acf4c1ab3: result
>
> Note that it would maybe be more interesting to add packetdrill test to
> validate this feature.
>
> Tests + export are going to be started soon.
>
> Cheers,
> Matt
> --
> Tessares | Belgium | Hybrid Access Solutions
> www.tessares.net
diff mbox series

Patch

diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 171039cbe9c4..14a290fae767 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -893,6 +893,7 @@  void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
 			mptcp_pm_add_addr_received(msk, &addr);
 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR);
 		} else {
+			mptcp_pm_del_add_timer(msk, &addr);
 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD);
 		}
 		mp_opt.add_addr = 0;
diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index 701972b55a45..6fad2cc4cf5d 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -31,6 +31,9 @@  struct mptcp_pm_addr_entry {
 struct mptcp_pm_add_entry {
 	struct list_head	list;
 	struct mptcp_addr_info	addr;
+	struct timer_list	add_timer;
+	struct mptcp_sock	*sock;
+	u8			retrans_times;
 };
 
 struct pm_nl_pernet {
@@ -46,6 +49,7 @@  struct pm_nl_pernet {
 };
 
 #define MPTCP_PM_ADDR_MAX	8
+#define ADD_ADDR_RETRANS_MAX	3
 
 static bool addresses_equal(const struct mptcp_addr_info *a,
 			    struct mptcp_addr_info *b, bool use_port)
@@ -183,23 +187,83 @@  static void check_work_pending(struct mptcp_sock *msk)
 		WRITE_ONCE(msk->pm.work_pending, false);
 }
 
-static bool lookup_anno_list_by_saddr(struct mptcp_sock *msk,
-				      struct mptcp_addr_info *addr)
+static struct mptcp_pm_add_entry *
+lookup_anno_list_by_saddr(struct mptcp_sock *msk,
+			  struct mptcp_addr_info *addr)
 {
-	struct mptcp_pm_add_entry *entry;
+	struct mptcp_pm_add_entry *entry, *ret = NULL;
 
 	list_for_each_entry(entry, &msk->pm.anno_list, list) {
-		if (addresses_equal(&entry->addr, addr, false))
-			return true;
+		if (addresses_equal(&entry->addr, addr, false)) {
+			ret = entry;
+			break;
+		}
 	}
 
-	return false;
+	return ret;
+}
+
+static void mptcp_pm_add_timer(struct timer_list *timer)
+{
+	struct mptcp_pm_add_entry *entry = from_timer(entry, timer, add_timer);
+	struct mptcp_sock *msk = entry->sock;
+	struct sock *sk = (struct sock *)msk;
+
+	pr_debug("msk=%p", msk);
+
+	if (!msk)
+		return;
+
+	if (sk->sk_state == TCP_CLOSE)
+		return;
+
+	if (!entry->addr.id)
+		return;
+
+	if (mptcp_pm_should_add_signal(msk)) {
+		sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8);
+		goto out;
+	}
+
+	spin_lock_bh(&msk->pm.lock);
+
+	if (!mptcp_pm_should_add_signal(msk)) {
+		pr_debug("retransmit ADD_ADDR id=%d", entry->addr.id);
+		mptcp_pm_announce_addr(msk, &entry->addr, false);
+		entry->retrans_times++;
+	}
+
+	if (entry->retrans_times < ADD_ADDR_RETRANS_MAX)
+		sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX);
+
+	spin_unlock_bh(&msk->pm.lock);
+
+out:
+	__sock_put(sk);
+}
+
+struct mptcp_pm_add_entry *
+mptcp_pm_del_add_timer(struct mptcp_sock *msk,
+		       struct mptcp_addr_info *addr)
+{
+	struct mptcp_pm_add_entry *entry;
+	struct sock *sk = (struct sock *)msk;
+
+	spin_lock_bh(&msk->pm.lock);
+	entry = lookup_anno_list_by_saddr(msk, addr);
+	spin_unlock_bh(&msk->pm.lock);
+
+	if (entry)
+		sk_stop_timer_sync(sk, &entry->add_timer);
+
+	return entry;
 }
 
 static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
 				     struct mptcp_pm_addr_entry *entry)
 {
 	struct mptcp_pm_add_entry *add_entry = NULL;
+	struct sock *sk = (struct sock *)msk;
 
 	if (lookup_anno_list_by_saddr(msk, &entry->addr))
 		return false;
@@ -210,21 +274,32 @@  static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
 
 	list_add(&add_entry->list, &msk->pm.anno_list);
 
+	add_entry->addr = entry->addr;
+	add_entry->sock = msk;
+	add_entry->retrans_times = 0;
+
+	timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0);
+	sk_reset_timer(sk, &add_entry->add_timer, jiffies + TCP_RTO_MAX);
+
 	return true;
 }
 
 void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
 {
 	struct mptcp_pm_add_entry *entry, *tmp;
+	struct sock *sk = (struct sock *)msk;
+	LIST_HEAD(free_list);
 
 	pr_debug("msk=%p", msk);
 
 	spin_lock_bh(&msk->pm.lock);
-	list_for_each_entry_safe(entry, tmp, &msk->pm.anno_list, list) {
-		list_del(&entry->list);
+	list_splice_init(&msk->pm.anno_list, &free_list);
+	spin_unlock_bh(&msk->pm.lock);
+
+	list_for_each_entry_safe(entry, tmp, &free_list, list) {
+		sk_stop_timer_sync(sk, &entry->add_timer);
 		kfree(entry);
 	}
-	spin_unlock_bh(&msk->pm.lock);
 }
 
 static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
@@ -659,14 +734,13 @@  __lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id)
 static bool remove_anno_list_by_saddr(struct mptcp_sock *msk,
 				      struct mptcp_addr_info *addr)
 {
-	struct mptcp_pm_add_entry *entry, *tmp;
+	struct mptcp_pm_add_entry *entry;
 
-	list_for_each_entry_safe(entry, tmp, &msk->pm.anno_list, list) {
-		if (addresses_equal(&entry->addr, addr, false)) {
-			list_del(&entry->list);
-			kfree(entry);
-			return true;
-		}
+	entry = mptcp_pm_del_add_timer(msk, addr);
+	if (entry) {
+		list_del(&entry->list);
+		kfree(entry);
+		return true;
 	}
 
 	return false;
@@ -678,11 +752,12 @@  static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk,
 {
 	bool ret;
 
-	spin_lock_bh(&msk->pm.lock);
 	ret = remove_anno_list_by_saddr(msk, addr);
-	if (ret || force)
+	if (ret || force) {
+		spin_lock_bh(&msk->pm.lock);
 		mptcp_pm_remove_addr(msk, addr->id);
-	spin_unlock_bh(&msk->pm.lock);
+		spin_unlock_bh(&msk->pm.lock);
+	}
 	return ret;
 }
 
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index db1e5de2fee7..7cfe52aeb2b8 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -444,6 +444,9 @@  void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
 				const struct mptcp_addr_info *addr);
 void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id);
 void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
+struct mptcp_pm_add_entry *
+mptcp_pm_del_add_timer(struct mptcp_sock *msk,
+		       struct mptcp_addr_info *addr);
 
 int mptcp_pm_announce_addr(struct mptcp_sock *msk,
 			   const struct mptcp_addr_info *addr,