mptcp: Retransmit DATA_FIN
authorMat Martineau <mathew.j.martineau@linux.intel.com>
Fri, 23 Apr 2021 16:40:33 +0000 (09:40 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 23 Apr 2021 21:03:02 +0000 (14:03 -0700)
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: 43b54c6ee382 ("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>
net/mptcp/protocol.c

index 4bde960..61329b8 100644 (file)
@@ -399,6 +399,14 @@ static bool mptcp_pending_data_fin(struct sock *sk, u64 *seq)
        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)
 {
        long tout = ssk && inet_csk(ssk)->icsk_pending ?
@@ -1052,7 +1060,7 @@ out:
        }
 
        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);
        } else {
                mptcp_reset_timer(sk);
@@ -2276,8 +2284,19 @@ static void __mptcp_retrans(struct sock *sk)
 
        __mptcp_clean_una_wakeup(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;
+       }
 
        ssk = mptcp_subflow_get_retrans(msk);
        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);
                        mptcp_set_timeout(sk, ssk);
                        tcp_send_ack(ssk);
+                       if (!mptcp_timer_pending(sk))
+                               mptcp_reset_timer(sk);
                }
                break;
        }