mptcp: Retransmit DATA_FIN
With this change, the MPTCP-level retransmission timer is used to resend
DATA_FIN. The retranmit timer is not stopped while waiting for a
MPTCP-level ACK of DATA_FIN, and retransmitted DATA_FINs are sent on all
subflows. The retry interval starts at TCP_RTO_MIN and then doubles on
each attempt, up to TCP_RTO_MAX.
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/146
Fixes: 43b54c6ee3
("mptcp: Use full MPTCP-level disconnect state machine")
Acked-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
d13f048dd4
Коммит
6477dd39e6
|
@ -399,6 +399,14 @@ static bool mptcp_pending_data_fin(struct sock *sk, u64 *seq)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mptcp_set_datafin_timeout(const struct sock *sk)
|
||||||
|
{
|
||||||
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
|
|
||||||
|
mptcp_sk(sk)->timer_ival = min(TCP_RTO_MAX,
|
||||||
|
TCP_RTO_MIN << icsk->icsk_retransmits);
|
||||||
|
}
|
||||||
|
|
||||||
static void mptcp_set_timeout(const struct sock *sk, const struct sock *ssk)
|
static void mptcp_set_timeout(const struct sock *sk, const struct sock *ssk)
|
||||||
{
|
{
|
||||||
long tout = ssk && inet_csk(ssk)->icsk_pending ?
|
long tout = ssk && inet_csk(ssk)->icsk_pending ?
|
||||||
|
@ -1052,7 +1060,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snd_una == READ_ONCE(msk->snd_nxt)) {
|
if (snd_una == READ_ONCE(msk->snd_nxt)) {
|
||||||
if (msk->timer_ival)
|
if (msk->timer_ival && !mptcp_data_fin_enabled(msk))
|
||||||
mptcp_stop_timer(sk);
|
mptcp_stop_timer(sk);
|
||||||
} else {
|
} else {
|
||||||
mptcp_reset_timer(sk);
|
mptcp_reset_timer(sk);
|
||||||
|
@ -2276,8 +2284,19 @@ static void __mptcp_retrans(struct sock *sk)
|
||||||
|
|
||||||
__mptcp_clean_una_wakeup(sk);
|
__mptcp_clean_una_wakeup(sk);
|
||||||
dfrag = mptcp_rtx_head(sk);
|
dfrag = mptcp_rtx_head(sk);
|
||||||
if (!dfrag)
|
if (!dfrag) {
|
||||||
|
if (mptcp_data_fin_enabled(msk)) {
|
||||||
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
|
|
||||||
|
icsk->icsk_retransmits++;
|
||||||
|
mptcp_set_datafin_timeout(sk);
|
||||||
|
mptcp_send_ack(msk);
|
||||||
|
|
||||||
|
goto reset_timer;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ssk = mptcp_subflow_get_retrans(msk);
|
ssk = mptcp_subflow_get_retrans(msk);
|
||||||
if (!ssk)
|
if (!ssk)
|
||||||
|
@ -2460,6 +2479,8 @@ void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
|
||||||
pr_debug("Sending DATA_FIN on subflow %p", ssk);
|
pr_debug("Sending DATA_FIN on subflow %p", ssk);
|
||||||
mptcp_set_timeout(sk, ssk);
|
mptcp_set_timeout(sk, ssk);
|
||||||
tcp_send_ack(ssk);
|
tcp_send_ack(ssk);
|
||||||
|
if (!mptcp_timer_pending(sk))
|
||||||
|
mptcp_reset_timer(sk);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче