Commit fc2ea6ab authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'mptcp-more-fixes-for-v6-5'

Matthieu Baerts says:

====================
mptcp: more fixes for v6.5

Here is a new batch of fixes related to MPTCP for v6.5 and older.

Patches 1 and 2 fix issues with MPTCP Join selftest when manually
launched with '-i' parameter to use 'ip mptcp' tool instead of the
dedicated one (pm_nl_ctl). The issues have been there since v5.18.

Thank you Andrea for your first contributions to MPTCP code in the
upstream kernel!

Patch 3 avoids corrupting the data stream when trying to reset
connections that have fallen back to TCP. This can happen from v6.1.

Patch 4 fixes a race when doing a disconnect() and an accept() in
parallel on a listener socket. The issue only happens in rare cases if
the user is really unlucky since a fix that landed in v6.3 but
backported up to v6.1.
====================

Link: https://lore.kernel.org/r/20230803-upstream-net-20230803-misc-fixes-6-5-v1-0-6671b1ab11cc@tessares.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents ec935188 511b90e3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2335,7 +2335,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,

	lock_sock_nested(ssk, SINGLE_DEPTH_NESTING);

	if (flags & MPTCP_CF_FASTCLOSE) {
	if ((flags & MPTCP_CF_FASTCLOSE) && !__mptcp_check_fallback(msk)) {
		/* be sure to force the tcp_disconnect() path,
		 * to generate the egress reset
		 */
+0 −1
Original line number Diff line number Diff line
@@ -325,7 +325,6 @@ struct mptcp_sock {
	u32		subflow_id;
	u32		setsockopt_seq;
	char		ca_name[TCP_CA_NAME_MAX];
	struct mptcp_sock	*dl_next;
};

#define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock)
+29 −29
Original line number Diff line number Diff line
@@ -1793,16 +1793,31 @@ static void subflow_state_change(struct sock *sk)
void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_ssk)
{
	struct request_sock_queue *queue = &inet_csk(listener_ssk)->icsk_accept_queue;
	struct mptcp_sock *msk, *next, *head = NULL;
	struct request_sock *req;
	struct sock *sk;
	struct request_sock *req, *head, *tail;
	struct mptcp_subflow_context *subflow;
	struct sock *sk, *ssk;

	/* build a list of all unaccepted mptcp sockets */
	/* Due to lock dependencies no relevant lock can be acquired under rskq_lock.
	 * Splice the req list, so that accept() can not reach the pending ssk after
	 * the listener socket is released below.
	 */
	spin_lock_bh(&queue->rskq_lock);
	for (req = queue->rskq_accept_head; req; req = req->dl_next) {
		struct mptcp_subflow_context *subflow;
		struct sock *ssk = req->sk;
	head = queue->rskq_accept_head;
	tail = queue->rskq_accept_tail;
	queue->rskq_accept_head = NULL;
	queue->rskq_accept_tail = NULL;
	spin_unlock_bh(&queue->rskq_lock);

	if (!head)
		return;

	/* can't acquire the msk socket lock under the subflow one,
	 * or will cause ABBA deadlock
	 */
	release_sock(listener_ssk);

	for (req = head; req; req = req->dl_next) {
		ssk = req->sk;
		if (!sk_is_mptcp(ssk))
			continue;

@@ -1810,32 +1825,10 @@ void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_s
		if (!subflow || !subflow->conn)
			continue;

		/* skip if already in list */
		sk = subflow->conn;
		msk = mptcp_sk(sk);
		if (msk->dl_next || msk == head)
			continue;

		sock_hold(sk);
		msk->dl_next = head;
		head = msk;
	}
	spin_unlock_bh(&queue->rskq_lock);
	if (!head)
		return;

	/* can't acquire the msk socket lock under the subflow one,
	 * or will cause ABBA deadlock
	 */
	release_sock(listener_ssk);

	for (msk = head; msk; msk = next) {
		sk = (struct sock *)msk;

		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
		next = msk->dl_next;
		msk->dl_next = NULL;

		__mptcp_unaccepted_force_close(sk);
		release_sock(sk);

@@ -1859,6 +1852,13 @@ void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_s

	/* we are still under the listener msk socket lock */
	lock_sock_nested(listener_ssk, SINGLE_DEPTH_NESTING);

	/* restore the listener queue, to let the TCP code clean it up */
	spin_lock_bh(&queue->rskq_lock);
	WARN_ON_ONCE(queue->rskq_accept_head);
	queue->rskq_accept_head = head;
	queue->rskq_accept_tail = tail;
	spin_unlock_bh(&queue->rskq_lock);
}

static int subflow_ulp_init(struct sock *sk)
+4 −2
Original line number Diff line number Diff line
@@ -705,6 +705,7 @@ pm_nl_del_endpoint()
	local addr=$3

	if [ $ip_mptcp -eq 1 ]; then
		[ $id -ne 0 ] && addr=''
		ip -n $ns mptcp endpoint delete id $id $addr
	else
		ip netns exec $ns ./pm_nl_ctl del $id $addr
@@ -795,10 +796,11 @@ pm_nl_check_endpoint()
	fi

	if [ $ip_mptcp -eq 1 ]; then
		# get line and trim trailing whitespace
		line=$(ip -n $ns mptcp endpoint show $id)
		line="${line% }"
		# the dump order is: address id flags port dev
		expected_line="$addr"
		[ -n "$addr" ] && expected_line="$expected_line $addr"
		[ -n "$addr" ] && expected_line="$addr"
		expected_line="$expected_line $id"
		[ -n "$_flags" ] && expected_line="$expected_line ${_flags//","/" "}"
		[ -n "$dev" ] && expected_line="$expected_line $dev"