All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH mptcp-next v2 0/3] MP_FAIL echo and retrans
@ 2022-03-07 13:09 Geliang Tang
  2022-03-07 13:09 ` [PATCH mptcp-next v2 1/3] mptcp: add MP_FAIL response support Geliang Tang
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Geliang Tang @ 2022-03-07 13:09 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

v2:
 - don't clear mp_fail_response_expect flag.
 - add a helper mp_fail_response_expect_subflow to get the subflow,
   instead of using msk->first.
 - add locks as Mat suggested.
 - add a selftest.

Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/261

Geliang Tang (3):
  mptcp: add MP_FAIL response support
  selftests: mptcp: check MP_FAIL response mibs
  mptcp: reset the subflow when MP_FAIL is lost

 net/mptcp/pm.c                                | 14 ++++-
 net/mptcp/protocol.c                          | 63 ++++++++++++++++++-
 net/mptcp/protocol.h                          |  2 +
 net/mptcp/subflow.c                           |  3 +
 .../testing/selftests/net/mptcp/mptcp_join.sh | 19 +++++-
 5 files changed, 94 insertions(+), 7 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH mptcp-next v2 1/3] mptcp: add MP_FAIL response support
  2022-03-07 13:09 [PATCH mptcp-next v2 0/3] MP_FAIL echo and retrans Geliang Tang
@ 2022-03-07 13:09 ` Geliang Tang
  2022-03-07 13:09 ` [PATCH mptcp-next v2 2/3] selftests: mptcp: check MP_FAIL response mibs Geliang Tang
  2022-03-07 13:09 ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Geliang Tang
  2 siblings, 0 replies; 9+ messages in thread
From: Geliang Tang @ 2022-03-07 13:09 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

This patch added a new struct member mp_fail_response_expect in struct
mptcp_subflow_context to support MP_FAIL response. In the single subflow
with checksum error and contiguous data special case, a MP_FAIL sent in
response to another MP_FAIL.

Signed-off-by: Geliang Tang <geliang.tang@suse.com>
---
 net/mptcp/pm.c       | 9 +++++++--
 net/mptcp/protocol.h | 1 +
 net/mptcp/subflow.c  | 2 ++
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index d0d31d5c198a..7aae8c2e845b 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -279,8 +279,13 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 
 	pr_debug("fail_seq=%llu", fail_seq);
 
-	if (!mptcp_has_another_subflow(sk) && READ_ONCE(msk->allow_infinite_fallback))
-		subflow->send_infinite_map = 1;
+	if (!mptcp_has_another_subflow(sk) && READ_ONCE(msk->allow_infinite_fallback)) {
+		if (!subflow->mp_fail_response_expect) {
+			subflow->send_mp_fail = 1;
+			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX);
+			subflow->send_infinite_map = 1;
+		}
+	}
 }
 
 /* path manager helpers */
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index c8bada4537e2..39aa22595add 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -448,6 +448,7 @@ struct mptcp_subflow_context {
 		backup : 1,
 		send_mp_prio : 1,
 		send_mp_fail : 1,
+		mp_fail_response_expect : 1,
 		send_fastclose : 1,
 		send_infinite_map : 1,
 		rx_eof : 1,
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 30ffb00661bb..63a256a94b65 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -1217,6 +1217,8 @@ static bool subflow_check_data_avail(struct sock *ssk)
 				tcp_send_active_reset(ssk, GFP_ATOMIC);
 				while ((skb = skb_peek(&ssk->sk_receive_queue)))
 					sk_eat_skb(ssk, skb);
+			} else {
+				subflow->mp_fail_response_expect = 1;
 			}
 			WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
 			return true;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH mptcp-next v2 2/3] selftests: mptcp: check MP_FAIL response mibs
  2022-03-07 13:09 [PATCH mptcp-next v2 0/3] MP_FAIL echo and retrans Geliang Tang
  2022-03-07 13:09 ` [PATCH mptcp-next v2 1/3] mptcp: add MP_FAIL response support Geliang Tang
@ 2022-03-07 13:09 ` Geliang Tang
  2022-03-07 13:09 ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Geliang Tang
  2 siblings, 0 replies; 9+ messages in thread
From: Geliang Tang @ 2022-03-07 13:09 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

This patch added a new argument invert for chk_fail_nr to allow it can
check the MP_FAIL Tx and Rx mibs from the opposite direction. Used it
to check the MP_FAIL response mibs.

Signed-off-by: Geliang Tang <geliang.tang@suse.com>
---
 .../testing/selftests/net/mptcp/mptcp_join.sh | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
index 959e46122a84..02da0f7bd1b0 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
@@ -1055,11 +1055,21 @@ chk_fail_nr()
 {
 	local fail_tx=$1
 	local fail_rx=$2
+	local ns_invert=${3:-""}
 	local count
 	local dump_stats
+	local ns_tx=$ns1
+	local ns_rx=$ns2
+	local extra_msg=""
+
+	if [[ $ns_invert = "invert" ]]; then
+		ns_tx=$ns2
+		ns_rx=$ns1
+		extra_msg="   invert"
+	fi
 
 	printf "%-${nr_blank}s %s" " " "ftx"
-	count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPFailTx | awk '{print $2}')
+	count=$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPFailTx | awk '{print $2}')
 	[ -z "$count" ] && count=0
 	if [ "$count" != "$fail_tx" ]; then
 		echo "[fail] got $count MP_FAIL[s] TX expected $fail_tx"
@@ -1070,17 +1080,19 @@ chk_fail_nr()
 	fi
 
 	echo -n " - failrx"
-	count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtMPFailRx | awk '{print $2}')
+	count=$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPFailRx | awk '{print $2}')
 	[ -z "$count" ] && count=0
 	if [ "$count" != "$fail_rx" ]; then
 		echo "[fail] got $count MP_FAIL[s] RX expected $fail_rx"
 		fail_test
 		dump_stats=1
 	else
-		echo "[ ok ]"
+		echo -n "[ ok ]"
 	fi
 
 	[ "${dump_stats}" = 1 ] && dump_stats
+
+	echo "$extra_msg"
 }
 
 chk_fclose_nr()
@@ -2672,6 +2684,7 @@ fail_tests()
 	if reset_with_fail "Infinite map" 1; then
 		run_tests $ns1 $ns2 10.0.1.1 128
 		chk_join_nr 0 0 0 +1 +0 1 0 1 "$(pedit_action_pkts)"
+		chk_fail_nr 1 1 invert
 	fi
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost
  2022-03-07 13:09 [PATCH mptcp-next v2 0/3] MP_FAIL echo and retrans Geliang Tang
  2022-03-07 13:09 ` [PATCH mptcp-next v2 1/3] mptcp: add MP_FAIL response support Geliang Tang
  2022-03-07 13:09 ` [PATCH mptcp-next v2 2/3] selftests: mptcp: check MP_FAIL response mibs Geliang Tang
@ 2022-03-07 13:09 ` Geliang Tang
  2022-03-07 14:32   ` mptcp: reset the subflow when MP_FAIL is lost: Tests Results MPTCP CI
  2022-03-09  1:02   ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Mat Martineau
  2 siblings, 2 replies; 9+ messages in thread
From: Geliang Tang @ 2022-03-07 13:09 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

This patch reuses icsk_retransmit_timer to trigger a check if we have
not received a response from the peer after sending MP_FAIL. If the
peer doesn't respond properly, reset the subflow.

Signed-off-by: Geliang Tang <geliang.tang@suse.com>
---
 net/mptcp/pm.c       |  5 ++++
 net/mptcp/protocol.c | 63 ++++++++++++++++++++++++++++++++++++++++++--
 net/mptcp/protocol.h |  1 +
 net/mptcp/subflow.c  |  1 +
 4 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 7aae8c2e845b..2630018786c6 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -276,6 +276,7 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 {
 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
 	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
+	struct sock *s = (struct sock *)msk;
 
 	pr_debug("fail_seq=%llu", fail_seq);
 
@@ -284,6 +285,10 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 			subflow->send_mp_fail = 1;
 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX);
 			subflow->send_infinite_map = 1;
+		} else {
+			mptcp_data_lock(s);
+			sk_stop_timer(s, &msk->sk.icsk_retransmit_timer);
+			mptcp_data_unlock(s);
 		}
 	}
 }
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 3cb975227d12..8702f7123143 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -866,6 +866,59 @@ static void mptcp_reset_timer(struct sock *sk)
 	sk_reset_timer(sk, &icsk->icsk_retransmit_timer, jiffies + tout);
 }
 
+static struct mptcp_subflow_context *
+mp_fail_response_expect_subflow(struct mptcp_sock *msk)
+{
+	struct mptcp_subflow_context *subflow, *ret = NULL;
+
+	mptcp_for_each_subflow(msk, subflow) {
+		if (subflow->mp_fail_response_expect) {
+			ret = subflow;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void mptcp_mp_fail_timer(struct timer_list *t)
+{
+	struct inet_connection_sock *icsk = from_timer(icsk, t,
+						       icsk_retransmit_timer);
+	struct sock *sk = &icsk->icsk_inet.sk;
+	struct mptcp_sock *msk = mptcp_sk(sk);
+	struct mptcp_subflow_context *subflow;
+
+	if (!sk || inet_sk_state_load(sk) == TCP_CLOSE)
+		return;
+
+	spin_lock_bh(&msk->pm.lock);
+	subflow = mp_fail_response_expect_subflow(msk);
+	spin_unlock_bh(&msk->pm.lock);
+	if (subflow) {
+		struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+
+		pr_debug("MP_FAIL is lost, reset the subflow");
+		bh_lock_sock(ssk);
+		mptcp_subflow_reset(ssk);
+		bh_unlock_sock(ssk);
+	}
+	sock_put(sk);
+}
+
+void mptcp_setup_mp_fail_timer(struct mptcp_sock *msk)
+{
+	struct sock *sk = (struct sock *)msk;
+
+	mptcp_data_lock(sk);
+	/* re-use the csk retrans timer for MP_FAIL retrans */
+	sk_stop_timer(sk, &msk->sk.icsk_retransmit_timer);
+	timer_setup(&msk->sk.icsk_retransmit_timer, mptcp_mp_fail_timer, 0);
+	__mptcp_set_timeout(sk, TCP_RTO_MAX);
+	mptcp_reset_timer(sk);
+	mptcp_data_unlock(sk);
+}
+
 bool mptcp_schedule_work(struct sock *sk)
 {
 	if (inet_sk_state_load(sk) != TCP_CLOSE &&
@@ -1428,6 +1481,7 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
 	struct subflow_send_info send_info[SSK_MODE_MAX];
 	struct mptcp_subflow_context *subflow;
 	struct sock *sk = (struct sock *)msk;
+	u8 mp_fail_response_expect = 0;
 	u32 pace, burst, wmem;
 	int i, nr_active = 0;
 	struct sock *ssk;
@@ -1442,11 +1496,15 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
 		return sk_stream_memory_free(msk->first) ? msk->first : NULL;
 	}
 
+	if (mp_fail_response_expect_subflow(msk))
+		mp_fail_response_expect = 1;
+
 	/* re-use last subflow, if the burst allow that */
 	if (msk->last_snd && msk->snd_burst > 0 &&
 	    sk_stream_memory_free(msk->last_snd) &&
 	    mptcp_subflow_active(mptcp_subflow_ctx(msk->last_snd))) {
-		mptcp_set_timeout(sk);
+		if (!mp_fail_response_expect)
+			mptcp_set_timeout(sk);
 		return msk->last_snd;
 	}
 
@@ -1479,7 +1537,8 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
 			send_info[subflow->backup].linger_time = linger_time;
 		}
 	}
-	__mptcp_set_timeout(sk, tout);
+	if (!mp_fail_response_expect)
+		__mptcp_set_timeout(sk, tout);
 
 	/* pick the best backup if no other subflow is active */
 	if (!nr_active)
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 39aa22595add..313c1a6c616f 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -669,6 +669,7 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk);
 void mptcp_data_ready(struct sock *sk, struct sock *ssk);
 bool mptcp_finish_join(struct sock *sk);
 bool mptcp_schedule_work(struct sock *sk);
+void mptcp_setup_mp_fail_timer(struct mptcp_sock *msk);
 int mptcp_setsockopt(struct sock *sk, int level, int optname,
 		     sockptr_t optval, unsigned int optlen);
 int mptcp_getsockopt(struct sock *sk, int level, int optname,
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 63a256a94b65..960b161b1cb2 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -1219,6 +1219,7 @@ static bool subflow_check_data_avail(struct sock *ssk)
 					sk_eat_skb(ssk, skb);
 			} else {
 				subflow->mp_fail_response_expect = 1;
+				mptcp_setup_mp_fail_timer(msk);
 			}
 			WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
 			return true;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: mptcp: reset the subflow when MP_FAIL is lost: Tests Results
  2022-03-07 13:09 ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Geliang Tang
@ 2022-03-07 14:32   ` MPTCP CI
  2022-03-09  1:02   ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Mat Martineau
  1 sibling, 0 replies; 9+ messages in thread
From: MPTCP CI @ 2022-03-07 14:32 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

Hi Geliang,

Thank you for your modifications, that's great!

Our CI did some validations and here is its report:

- KVM Validation: normal:
  - Unstable: 1 failed test(s): selftest_mptcp_join 🔴:
  - Task: https://cirrus-ci.com/task/5236831624101888
  - Summary: https://api.cirrus-ci.com/v1/artifact/task/5236831624101888/summary/summary.txt

- KVM Validation: debug:
  - Unstable: 1 failed test(s): selftest_mptcp_join 🔴:
  - Task: https://cirrus-ci.com/task/6362731530944512
  - Summary: https://api.cirrus-ci.com/v1/artifact/task/6362731530944512/summary/summary.txt

Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/7eab38dd4d32

Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)

Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (Tessares)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost
  2022-03-07 13:09 ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Geliang Tang
  2022-03-07 14:32   ` mptcp: reset the subflow when MP_FAIL is lost: Tests Results MPTCP CI
@ 2022-03-09  1:02   ` Mat Martineau
  2022-03-09  1:06     ` Mat Martineau
  1 sibling, 1 reply; 9+ messages in thread
From: Mat Martineau @ 2022-03-09  1:02 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

On Mon, 7 Mar 2022, Geliang Tang wrote:

> This patch reuses icsk_retransmit_timer to trigger a check if we have
> not received a response from the peer after sending MP_FAIL. If the
> peer doesn't respond properly, reset the subflow.
>
> Signed-off-by: Geliang Tang <geliang.tang@suse.com>
> ---
> net/mptcp/pm.c       |  5 ++++
> net/mptcp/protocol.c | 63 ++++++++++++++++++++++++++++++++++++++++++--
> net/mptcp/protocol.h |  1 +
> net/mptcp/subflow.c  |  1 +
> 4 files changed, 68 insertions(+), 2 deletions(-)
>
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index 7aae8c2e845b..2630018786c6 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -276,6 +276,7 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
> {
> 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
> 	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
> +	struct sock *s = (struct sock *)msk;
>
> 	pr_debug("fail_seq=%llu", fail_seq);
>
> @@ -284,6 +285,10 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
> 			subflow->send_mp_fail = 1;
> 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX);
> 			subflow->send_infinite_map = 1;
> +		} else {
> +			mptcp_data_lock(s);
> +			sk_stop_timer(s, &msk->sk.icsk_retransmit_timer);
> +			mptcp_data_unlock(s);
> 		}
> 	}
> }
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 3cb975227d12..8702f7123143 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -866,6 +866,59 @@ static void mptcp_reset_timer(struct sock *sk)
> 	sk_reset_timer(sk, &icsk->icsk_retransmit_timer, jiffies + tout);
> }
>
> +static struct mptcp_subflow_context *
> +mp_fail_response_expect_subflow(struct mptcp_sock *msk)
> +{
> +	struct mptcp_subflow_context *subflow, *ret = NULL;
> +
> +	mptcp_for_each_subflow(msk, subflow) {
> +		if (subflow->mp_fail_response_expect) {
> +			ret = subflow;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static void mptcp_mp_fail_timer(struct timer_list *t)
> +{
> +	struct inet_connection_sock *icsk = from_timer(icsk, t,
> +						       icsk_retransmit_timer);
> +	struct sock *sk = &icsk->icsk_inet.sk;
> +	struct mptcp_sock *msk = mptcp_sk(sk);
> +	struct mptcp_subflow_context *subflow;
> +
> +	if (!sk || inet_sk_state_load(sk) == TCP_CLOSE)
> +		return;

Is it possible for sk to be NULL here? mptcp_timeout_timer() and 
mptcp_retransmit_timer() don't check for NULL.

Also, early return leaks a refcount on the sk (a sock_put() is always 
needed).

> +
> +	spin_lock_bh(&msk->pm.lock);
> +	subflow = mp_fail_response_expect_subflow(msk);
> +	spin_unlock_bh(&msk->pm.lock);

msk->conn_list is protected by the msk lock, so the pm.lock isn't going to 
protect it here.

I think if you used msk->sk_timer and a msk->flags bit, the existing 
mptcp_timeout_timer() handler could be used and some new code in 
mptcp_worker() could handle resetting the subflow. This would avoid a lot 
of locking here in the timer handler.

The timing for a missing MP_FAIL is not strict, so it doesn't seem 
important to handle it all in a low-level timer callback.


> +	if (subflow) {
> +		struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
> +
> +		pr_debug("MP_FAIL is lost, reset the subflow");
> +		bh_lock_sock(ssk);
> +		mptcp_subflow_reset(ssk);
> +		bh_unlock_sock(ssk);
> +	}
> +	sock_put(sk);
> +}
> +
> +void mptcp_setup_mp_fail_timer(struct mptcp_sock *msk)
> +{
> +	struct sock *sk = (struct sock *)msk;
> +
> +	mptcp_data_lock(sk);
> +	/* re-use the csk retrans timer for MP_FAIL retrans */
> +	sk_stop_timer(sk, &msk->sk.icsk_retransmit_timer);
> +	timer_setup(&msk->sk.icsk_retransmit_timer, mptcp_mp_fail_timer, 0);
> +	__mptcp_set_timeout(sk, TCP_RTO_MAX);
> +	mptcp_reset_timer(sk);
> +	mptcp_data_unlock(sk);
> +}
> +
> bool mptcp_schedule_work(struct sock *sk)
> {
> 	if (inet_sk_state_load(sk) != TCP_CLOSE &&
> @@ -1428,6 +1481,7 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
> 	struct subflow_send_info send_info[SSK_MODE_MAX];
> 	struct mptcp_subflow_context *subflow;
> 	struct sock *sk = (struct sock *)msk;
> +	u8 mp_fail_response_expect = 0;
> 	u32 pace, burst, wmem;
> 	int i, nr_active = 0;
> 	struct sock *ssk;
> @@ -1442,11 +1496,15 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
> 		return sk_stream_memory_free(msk->first) ? msk->first : NULL;
> 	}
>
> +	if (mp_fail_response_expect_subflow(msk))
> +		mp_fail_response_expect = 1;

Using sk_timer as I mention above will also make it unnecessary to add 
this check and all the mp_fail_response_expect logic to this function.

- Mat

> +
> 	/* re-use last subflow, if the burst allow that */
> 	if (msk->last_snd && msk->snd_burst > 0 &&
> 	    sk_stream_memory_free(msk->last_snd) &&
> 	    mptcp_subflow_active(mptcp_subflow_ctx(msk->last_snd))) {
> -		mptcp_set_timeout(sk);
> +		if (!mp_fail_response_expect)
> +			mptcp_set_timeout(sk);
> 		return msk->last_snd;
> 	}
>
> @@ -1479,7 +1537,8 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
> 			send_info[subflow->backup].linger_time = linger_time;
> 		}
> 	}
> -	__mptcp_set_timeout(sk, tout);
> +	if (!mp_fail_response_expect)
> +		__mptcp_set_timeout(sk, tout);
>
> 	/* pick the best backup if no other subflow is active */
> 	if (!nr_active)
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index 39aa22595add..313c1a6c616f 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -669,6 +669,7 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk);
> void mptcp_data_ready(struct sock *sk, struct sock *ssk);
> bool mptcp_finish_join(struct sock *sk);
> bool mptcp_schedule_work(struct sock *sk);
> +void mptcp_setup_mp_fail_timer(struct mptcp_sock *msk);
> int mptcp_setsockopt(struct sock *sk, int level, int optname,
> 		     sockptr_t optval, unsigned int optlen);
> int mptcp_getsockopt(struct sock *sk, int level, int optname,
> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
> index 63a256a94b65..960b161b1cb2 100644
> --- a/net/mptcp/subflow.c
> +++ b/net/mptcp/subflow.c
> @@ -1219,6 +1219,7 @@ static bool subflow_check_data_avail(struct sock *ssk)
> 					sk_eat_skb(ssk, skb);
> 			} else {
> 				subflow->mp_fail_response_expect = 1;
> +				mptcp_setup_mp_fail_timer(msk);
> 			}
> 			WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
> 			return true;
> -- 
> 2.34.1
>
>
>

--
Mat Martineau
Intel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost
  2022-03-09  1:02   ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Mat Martineau
@ 2022-03-09  1:06     ` Mat Martineau
  0 siblings, 0 replies; 9+ messages in thread
From: Mat Martineau @ 2022-03-09  1:06 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

On Tue, 8 Mar 2022, Mat Martineau wrote:

> On Mon, 7 Mar 2022, Geliang Tang wrote:
>
>> This patch reuses icsk_retransmit_timer to trigger a check if we have
>> not received a response from the peer after sending MP_FAIL. If the
>> peer doesn't respond properly, reset the subflow.
>> 
>> Signed-off-by: Geliang Tang <geliang.tang@suse.com>
>> ---
>> net/mptcp/pm.c       |  5 ++++
>> net/mptcp/protocol.c | 63 ++++++++++++++++++++++++++++++++++++++++++--
>> net/mptcp/protocol.h |  1 +
>> net/mptcp/subflow.c  |  1 +
>> 4 files changed, 68 insertions(+), 2 deletions(-)
>> 
>> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
>> index 7aae8c2e845b..2630018786c6 100644
>> --- a/net/mptcp/pm.c
>> +++ b/net/mptcp/pm.c
>> @@ -276,6 +276,7 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 
>> fail_seq)
>> {
>> 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
>> 	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
>> +	struct sock *s = (struct sock *)msk;
>>
>> 	pr_debug("fail_seq=%llu", fail_seq);
>> 
>> @@ -284,6 +285,10 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 
>> fail_seq)
>> 			subflow->send_mp_fail = 1;
>> 			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX);
>> 			subflow->send_infinite_map = 1;
>> +		} else {
>> +			mptcp_data_lock(s);
>> +			sk_stop_timer(s, &msk->sk.icsk_retransmit_timer);
>> +			mptcp_data_unlock(s);
>> 		}
>> 	}
>> }
>> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
>> index 3cb975227d12..8702f7123143 100644
>> --- a/net/mptcp/protocol.c
>> +++ b/net/mptcp/protocol.c
>> @@ -866,6 +866,59 @@ static void mptcp_reset_timer(struct sock *sk)
>> 	sk_reset_timer(sk, &icsk->icsk_retransmit_timer, jiffies + tout);
>> }
>> 
>> +static struct mptcp_subflow_context *
>> +mp_fail_response_expect_subflow(struct mptcp_sock *msk)
>> +{
>> +	struct mptcp_subflow_context *subflow, *ret = NULL;
>> +
>> +	mptcp_for_each_subflow(msk, subflow) {
>> +		if (subflow->mp_fail_response_expect) {

One more thing: if this value is read without the subflow lock held, it 
would be better to use READ_ONCE/WRITE_ONCE. That would also require it to 
be a non-bitfield struct member.

- Mat

>> +			ret = subflow;
>> +			break;
>> +		}
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static void mptcp_mp_fail_timer(struct timer_list *t)
>> +{
>> +	struct inet_connection_sock *icsk = from_timer(icsk, t,
>> + 
>> icsk_retransmit_timer);
>> +	struct sock *sk = &icsk->icsk_inet.sk;
>> +	struct mptcp_sock *msk = mptcp_sk(sk);
>> +	struct mptcp_subflow_context *subflow;
>> +
>> +	if (!sk || inet_sk_state_load(sk) == TCP_CLOSE)
>> +		return;
>
> Is it possible for sk to be NULL here? mptcp_timeout_timer() and 
> mptcp_retransmit_timer() don't check for NULL.
>
> Also, early return leaks a refcount on the sk (a sock_put() is always 
> needed).
>
>> +
>> +	spin_lock_bh(&msk->pm.lock);
>> +	subflow = mp_fail_response_expect_subflow(msk);
>> +	spin_unlock_bh(&msk->pm.lock);
>
> msk->conn_list is protected by the msk lock, so the pm.lock isn't going to 
> protect it here.
>
> I think if you used msk->sk_timer and a msk->flags bit, the existing 
> mptcp_timeout_timer() handler could be used and some new code in 
> mptcp_worker() could handle resetting the subflow. This would avoid a lot of 
> locking here in the timer handler.
>
> The timing for a missing MP_FAIL is not strict, so it doesn't seem important 
> to handle it all in a low-level timer callback.
>
>
>> +	if (subflow) {
>> +		struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
>> +
>> +		pr_debug("MP_FAIL is lost, reset the subflow");
>> +		bh_lock_sock(ssk);
>> +		mptcp_subflow_reset(ssk);
>> +		bh_unlock_sock(ssk);
>> +	}
>> +	sock_put(sk);
>> +}
>> +
>> +void mptcp_setup_mp_fail_timer(struct mptcp_sock *msk)
>> +{
>> +	struct sock *sk = (struct sock *)msk;
>> +
>> +	mptcp_data_lock(sk);
>> +	/* re-use the csk retrans timer for MP_FAIL retrans */
>> +	sk_stop_timer(sk, &msk->sk.icsk_retransmit_timer);
>> +	timer_setup(&msk->sk.icsk_retransmit_timer, mptcp_mp_fail_timer, 0);
>> +	__mptcp_set_timeout(sk, TCP_RTO_MAX);
>> +	mptcp_reset_timer(sk);
>> +	mptcp_data_unlock(sk);
>> +}
>> +
>> bool mptcp_schedule_work(struct sock *sk)
>> {
>> 	if (inet_sk_state_load(sk) != TCP_CLOSE &&
>> @@ -1428,6 +1481,7 @@ static struct sock *mptcp_subflow_get_send(struct 
>> mptcp_sock *msk)
>> 	struct subflow_send_info send_info[SSK_MODE_MAX];
>> 	struct mptcp_subflow_context *subflow;
>> 	struct sock *sk = (struct sock *)msk;
>> +	u8 mp_fail_response_expect = 0;
>> 	u32 pace, burst, wmem;
>> 	int i, nr_active = 0;
>> 	struct sock *ssk;
>> @@ -1442,11 +1496,15 @@ static struct sock *mptcp_subflow_get_send(struct 
>> mptcp_sock *msk)
>> 		return sk_stream_memory_free(msk->first) ? msk->first : NULL;
>> 	}
>> 
>> +	if (mp_fail_response_expect_subflow(msk))
>> +		mp_fail_response_expect = 1;
>
> Using sk_timer as I mention above will also make it unnecessary to add this 
> check and all the mp_fail_response_expect logic to this function.
>
> - Mat
>
>> +
>> 	/* re-use last subflow, if the burst allow that */
>> 	if (msk->last_snd && msk->snd_burst > 0 &&
>> 	    sk_stream_memory_free(msk->last_snd) &&
>> 	    mptcp_subflow_active(mptcp_subflow_ctx(msk->last_snd))) {
>> -		mptcp_set_timeout(sk);
>> +		if (!mp_fail_response_expect)
>> +			mptcp_set_timeout(sk);
>> 		return msk->last_snd;
>> 	}
>> 
>> @@ -1479,7 +1537,8 @@ static struct sock *mptcp_subflow_get_send(struct 
>> mptcp_sock *msk)
>> 			send_info[subflow->backup].linger_time = linger_time;
>> 		}
>> 	}
>> -	__mptcp_set_timeout(sk, tout);
>> +	if (!mp_fail_response_expect)
>> +		__mptcp_set_timeout(sk, tout);
>>
>> 	/* pick the best backup if no other subflow is active */
>> 	if (!nr_active)
>> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
>> index 39aa22595add..313c1a6c616f 100644
>> --- a/net/mptcp/protocol.h
>> +++ b/net/mptcp/protocol.h
>> @@ -669,6 +669,7 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const 
>> struct sock *ssk);
>> void mptcp_data_ready(struct sock *sk, struct sock *ssk);
>> bool mptcp_finish_join(struct sock *sk);
>> bool mptcp_schedule_work(struct sock *sk);
>> +void mptcp_setup_mp_fail_timer(struct mptcp_sock *msk);
>> int mptcp_setsockopt(struct sock *sk, int level, int optname,
>> 		     sockptr_t optval, unsigned int optlen);
>> int mptcp_getsockopt(struct sock *sk, int level, int optname,
>> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
>> index 63a256a94b65..960b161b1cb2 100644
>> --- a/net/mptcp/subflow.c
>> +++ b/net/mptcp/subflow.c
>> @@ -1219,6 +1219,7 @@ static bool subflow_check_data_avail(struct sock 
>> *ssk)
>> 					sk_eat_skb(ssk, skb);
>> 			} else {
>> 				subflow->mp_fail_response_expect = 1;
>> +				mptcp_setup_mp_fail_timer(msk);
>> 			}
>> 			WRITE_ONCE(subflow->data_avail, 
>> MPTCP_SUBFLOW_NODATA);
>> 			return true;
>> -- 
>> 2.34.1
>> 
>> 
>> 
>
> --
> Mat Martineau
> Intel
>
>

--
Mat Martineau
Intel

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: mptcp: reset the subflow when MP_FAIL is lost: Tests Results
  2022-03-03  6:04 [PATCH mptcp-next 2/2] " Geliang Tang
  2022-03-03  6:48 ` mptcp: reset the subflow when MP_FAIL is lost: Tests Results MPTCP CI
@ 2022-03-07 12:33 ` MPTCP CI
  1 sibling, 0 replies; 9+ messages in thread
From: MPTCP CI @ 2022-03-07 12:33 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

Hi Geliang,

Thank you for your modifications, that's great!

Our CI did some validations and here is its report:

- KVM Validation: normal:
  - Success! ✅:
  - Task: https://cirrus-ci.com/task/5749632264306688
  - Summary: https://api.cirrus-ci.com/v1/artifact/task/5749632264306688/summary/summary.txt

- KVM Validation: debug:
  - Unstable: 1 failed test(s): selftest_diag 🔴:
  - Task: https://cirrus-ci.com/task/4623732357464064
  - Summary: https://api.cirrus-ci.com/v1/artifact/task/4623732357464064/summary/summary.txt

Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/e77e2e4ab530

Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)

Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (Tessares)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: mptcp: reset the subflow when MP_FAIL is lost: Tests Results
  2022-03-03  6:04 [PATCH mptcp-next 2/2] " Geliang Tang
@ 2022-03-03  6:48 ` MPTCP CI
  2022-03-07 12:33 ` MPTCP CI
  1 sibling, 0 replies; 9+ messages in thread
From: MPTCP CI @ 2022-03-03  6:48 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

Hi Geliang,

Thank you for your modifications, that's great!

Our CI did some validations and here is its report:

- {"code":404,"message":
  - "HTTP 404 Not Found"}:
  - Task: https://cirrus-ci.com/task/6506211624353792
  - Summary: https://api.cirrus-ci.com/v1/artifact/task/6506211624353792/summary/summary.txt

- {"code":404,"message":
  - "HTTP 404 Not Found"}:
  - Task: https://cirrus-ci.com/task/5189979209990144
  - Summary: https://api.cirrus-ci.com/v1/artifact/task/5189979209990144/summary/summary.txt

Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/e77e2e4ab530

Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)

Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (Tessares)

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-03-09  1:06 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-07 13:09 [PATCH mptcp-next v2 0/3] MP_FAIL echo and retrans Geliang Tang
2022-03-07 13:09 ` [PATCH mptcp-next v2 1/3] mptcp: add MP_FAIL response support Geliang Tang
2022-03-07 13:09 ` [PATCH mptcp-next v2 2/3] selftests: mptcp: check MP_FAIL response mibs Geliang Tang
2022-03-07 13:09 ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Geliang Tang
2022-03-07 14:32   ` mptcp: reset the subflow when MP_FAIL is lost: Tests Results MPTCP CI
2022-03-09  1:02   ` [PATCH mptcp-next v2 3/3] mptcp: reset the subflow when MP_FAIL is lost Mat Martineau
2022-03-09  1:06     ` Mat Martineau
  -- strict thread matches above, loose matches on Subject: below --
2022-03-03  6:04 [PATCH mptcp-next 2/2] " Geliang Tang
2022-03-03  6:48 ` mptcp: reset the subflow when MP_FAIL is lost: Tests Results MPTCP CI
2022-03-07 12:33 ` MPTCP CI

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.