Commit a29b56c4 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mptcp-Improve-DATA_FIN-transmission'



Mat Martineau says:

====================
mptcp: Improve DATA_FIN transmission

MPTCP's DATA_FIN flag is sent in a DSS option when closing the
MPTCP-level connection. This patch series prepares for correct DATA_FIN
handling across multiple subflows (where individual subflows may
disconnect without closing the entire MPTCP connection) by changing the
way the MPTCP-level socket requests a DATA_FIN on a subflow and
propagates the necessary data for the TCP option.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0a303214 6d37a0b8
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -304,21 +304,22 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
				 struct mptcp_ext *ext)
{
	ext->data_fin = 1;

	if (!ext->use_map) {
		/* RFC6824 requires a DSS mapping with specific values
		 * if DATA_FIN is set but no data payload is mapped
		 */
		ext->data_fin = 1;
		ext->use_map = 1;
		ext->dsn64 = 1;
		ext->data_seq = mptcp_sk(subflow->conn)->write_seq;
		ext->data_seq = subflow->data_fin_tx_seq;
		ext->subflow_seq = 0;
		ext->data_len = 1;
	} else {
		/* If there's an existing DSS mapping, DATA_FIN consumes
		 * 1 additional byte of mapping space.
	} else if (ext->data_seq + ext->data_len == subflow->data_fin_tx_seq) {
		/* If there's an existing DSS mapping and it is the
		 * final mapping, DATA_FIN consumes 1 additional byte of
		 * mapping space.
		 */
		ext->data_fin = 1;
		ext->data_len++;
	}
}
@@ -354,8 +355,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
		if (mpext)
			opts->ext_copy = *mpext;

		if (skb && tcp_fin &&
		    subflow->conn->sk_state != TCP_ESTABLISHED)
		if (skb && tcp_fin && subflow->data_fin_tx_enable)
			mptcp_write_data_fin(subflow, &opts->ext_copy);
		ret = true;
	}
+27 −5
Original line number Diff line number Diff line
@@ -419,6 +419,15 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
		return -EOPNOTSUPP;

	lock_sock(sk);

	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);

	if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
		ret = sk_stream_wait_connect(sk, &timeo);
		if (ret)
			goto out;
	}

	ssock = __mptcp_tcp_fallback(msk);
	if (unlikely(ssock)) {
fallback:
@@ -427,8 +436,6 @@ fallback:
		return ret >= 0 ? ret + copied : (copied ? copied : ret);
	}

	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);

	ssk = mptcp_subflow_get(msk);
	if (!ssk) {
		release_sock(sk);
@@ -460,6 +467,7 @@ fallback:

	ssk_check_wmem(msk, ssk);
	release_sock(ssk);
out:
	release_sock(sk);
	return ret;
}
@@ -712,7 +720,8 @@ static void mptcp_cancel_work(struct sock *sk)
		sock_put(sk);
}

static void mptcp_subflow_shutdown(struct sock *ssk, int how)
static void mptcp_subflow_shutdown(struct sock *ssk, int how,
				   bool data_fin_tx_enable, u64 data_fin_tx_seq)
{
	lock_sock(ssk);

@@ -725,6 +734,14 @@ static void mptcp_subflow_shutdown(struct sock *ssk, int how)
		tcp_disconnect(ssk, O_NONBLOCK);
		break;
	default:
		if (data_fin_tx_enable) {
			struct mptcp_subflow_context *subflow;

			subflow = mptcp_subflow_ctx(ssk);
			subflow->data_fin_tx_seq = data_fin_tx_seq;
			subflow->data_fin_tx_enable = 1;
		}

		ssk->sk_shutdown |= how;
		tcp_shutdown(ssk, how);
		break;
@@ -741,6 +758,7 @@ static void mptcp_close(struct sock *sk, long timeout)
	struct mptcp_subflow_context *subflow, *tmp;
	struct mptcp_sock *msk = mptcp_sk(sk);
	LIST_HEAD(conn_list);
	u64 data_fin_tx_seq;

	lock_sock(sk);

@@ -749,11 +767,15 @@ static void mptcp_close(struct sock *sk, long timeout)

	list_splice_init(&msk->conn_list, &conn_list);

	data_fin_tx_seq = msk->write_seq;

	release_sock(sk);

	list_for_each_entry_safe(subflow, tmp, &conn_list, node) {
		struct sock *ssk = mptcp_subflow_tcp_sock(subflow);

		subflow->data_fin_tx_seq = data_fin_tx_seq;
		subflow->data_fin_tx_enable = 1;
		__mptcp_close_ssk(sk, ssk, subflow, timeout);
	}

@@ -846,7 +868,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
			*err = -ENOBUFS;
			local_bh_enable();
			release_sock(sk);
			mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1);
			mptcp_subflow_shutdown(newsk, SHUT_RDWR + 1, 0, 0);
			tcp_close(newsk, 0);
			return NULL;
		}
@@ -1301,7 +1323,7 @@ static int mptcp_shutdown(struct socket *sock, int how)
	mptcp_for_each_subflow(msk, subflow) {
		struct sock *tcp_sk = mptcp_subflow_tcp_sock(subflow);

		mptcp_subflow_shutdown(tcp_sk, how);
		mptcp_subflow_shutdown(tcp_sk, how, 1, msk->write_seq);
	}

out_unlock:
+2 −0
Original line number Diff line number Diff line
@@ -125,7 +125,9 @@ struct mptcp_subflow_context {
		mpc_map : 1,
		data_avail : 1,
		rx_eof : 1,
		data_fin_tx_enable : 1,
		can_ack : 1;	    /* only after processing the remote a key */
	u64	data_fin_tx_seq;

	struct	sock *tcp_sock;	    /* tcp sk backpointer */
	struct	sock *conn;	    /* parent mptcp_sock */