This patch added a new msk->flags bit MPTCP_FAIL_NO_RESPONSE, then reused
sk_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 | 2 ++
net/mptcp/protocol.c | 21 +++++++++++++++++++++
net/mptcp/protocol.h | 1 +
net/mptcp/subflow.c | 2 ++
4 files changed, 26 insertions(+)
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index c4622b07b7f5..c41aca97ba36 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -284,6 +284,8 @@ 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 {
+ clear_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags);
}
}
}
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 3cb975227d12..6ff7e6eb44ee 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -2494,6 +2494,24 @@ static void __mptcp_retrans(struct sock *sk)
mptcp_reset_timer(sk);
}
+static void mptcp_mp_fail_no_response(struct mptcp_sock *msk)
+{
+ struct mptcp_subflow_context *subflow;
+
+ mptcp_for_each_subflow(msk, subflow) {
+ if (READ_ONCE(subflow->mp_fail_response_expect)) {
+ struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+ bool slow;
+
+ pr_debug("MP_FAIL doesn't respond, reset the subflow");
+ slow = lock_sock_fast(ssk);
+ mptcp_subflow_reset(ssk);
+ unlock_sock_fast(ssk, slow);
+ break;
+ }
+ }
+}
+
static void mptcp_worker(struct work_struct *work)
{
struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);
@@ -2534,6 +2552,9 @@ static void mptcp_worker(struct work_struct *work)
if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
__mptcp_retrans(sk);
+ if (test_and_clear_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags))
+ mptcp_mp_fail_no_response(msk);
+
unlock:
release_sock(sk);
sock_put(sk);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 83f0205f0d95..bf58d3c886f5 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -116,6 +116,7 @@
#define MPTCP_WORK_EOF 3
#define MPTCP_FALLBACK_DONE 4
#define MPTCP_WORK_CLOSE_SUBFLOW 5
+#define MPTCP_FAIL_NO_RESPONSE 6
/* MPTCP socket release cb flags */
#define MPTCP_PUSH_PENDING 1
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index ca2352ad20d4..5a7aa6e37ca6 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -1009,6 +1009,7 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
pr_debug("infinite mapping received");
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPRX);
subflow->map_data_len = 0;
+ clear_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags);
return MAPPING_INVALID;
}
@@ -1219,6 +1220,7 @@ static bool subflow_check_data_avail(struct sock *ssk)
sk_eat_skb(ssk, skb);
} else {
WRITE_ONCE(subflow->mp_fail_response_expect, true);
+ set_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags);
}
WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
return true;
--
2.34.1
On Wed, 9 Mar 2022, Geliang Tang wrote:
> This patch added a new msk->flags bit MPTCP_FAIL_NO_RESPONSE, then reused
> sk_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.
>
I don't see the sk_timer use?
> Signed-off-by: Geliang Tang <geliang.tang@suse.com>
> ---
> net/mptcp/pm.c | 2 ++
> net/mptcp/protocol.c | 21 +++++++++++++++++++++
> net/mptcp/protocol.h | 1 +
> net/mptcp/subflow.c | 2 ++
> 4 files changed, 26 insertions(+)
>
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index c4622b07b7f5..c41aca97ba36 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -284,6 +284,8 @@ 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 {
> + clear_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags);
Here I think you'd clear the sk_timer (if socket not closed).
> }
> }
> }
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 3cb975227d12..6ff7e6eb44ee 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -2494,6 +2494,24 @@ static void __mptcp_retrans(struct sock *sk)
> mptcp_reset_timer(sk);
> }
>
> +static void mptcp_mp_fail_no_response(struct mptcp_sock *msk)
> +{
> + struct mptcp_subflow_context *subflow;
> +
> + mptcp_for_each_subflow(msk, subflow) {
> + if (READ_ONCE(subflow->mp_fail_response_expect)) {
> + struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
> + bool slow;
> +
> + pr_debug("MP_FAIL doesn't respond, reset the subflow");
> + slow = lock_sock_fast(ssk);
> + mptcp_subflow_reset(ssk);
> + unlock_sock_fast(ssk, slow);
> + break;
> + }
> + }
> +}
> +
> static void mptcp_worker(struct work_struct *work)
> {
> struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);
> @@ -2534,6 +2552,9 @@ static void mptcp_worker(struct work_struct *work)
> if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
> __mptcp_retrans(sk);
>
> + if (test_and_clear_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags))
> + mptcp_mp_fail_no_response(msk);
> +
Without the other suggested changes, this would reset the subflow if the
worker runs for any reason (and at any time) after MP_FAIL is sent.
> unlock:
> release_sock(sk);
> sock_put(sk);
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index 83f0205f0d95..bf58d3c886f5 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -116,6 +116,7 @@
> #define MPTCP_WORK_EOF 3
> #define MPTCP_FALLBACK_DONE 4
> #define MPTCP_WORK_CLOSE_SUBFLOW 5
> +#define MPTCP_FAIL_NO_RESPONSE 6
>
> /* MPTCP socket release cb flags */
> #define MPTCP_PUSH_PENDING 1
> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
> index ca2352ad20d4..5a7aa6e37ca6 100644
> --- a/net/mptcp/subflow.c
> +++ b/net/mptcp/subflow.c
> @@ -1009,6 +1009,7 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
> pr_debug("infinite mapping received");
> MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPRX);
> subflow->map_data_len = 0;
> + clear_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags);
Another spot to clear the timer rather than this flag.
> return MAPPING_INVALID;
> }
>
> @@ -1219,6 +1220,7 @@ static bool subflow_check_data_avail(struct sock *ssk)
> sk_eat_skb(ssk, skb);
> } else {
> WRITE_ONCE(subflow->mp_fail_response_expect, true);
> + set_bit(MPTCP_FAIL_NO_RESPONSE, &msk->flags);
Here, start the timer. In the timer handler, set MPTCP_FAIL_NO_RESPONSE
flag (with required locking) if it was an MP_FAIL timeout.
> }
> WRITE_ONCE(subflow->data_avail, MPTCP_SUBFLOW_NODATA);
> return true;
> --
> 2.34.1
>
>
>
--
Mat Martineau
Intel
© 2016 - 2026 Red Hat, Inc.