Commit 1c1f14f9 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mptcp-fixes-for-v6-6'

Mat Martineau says:

====================
mptcp: Fixes for v6.6

Patch 1 corrects the logic for MP_JOIN tests where 0 RSTs are expected.

Patch 2 ensures MPTCP packets are not incorrectly coalesced in the TCP
backlog queue.

Patch 3 avoids a zero-window probe and associated WARN_ON_ONCE() in an
expected MPTCP reinjection scenario.

Patches 4 & 5 allow an initial MPTCP subflow to be closed cleanly
instead of always sending RST. Associated selftest is updated.
====================

Link: https://lore.kernel.org/r/20231018-send-net-20231018-v1-0-17ecb002e41d@kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 389db4fd 2cfaa8b3
...@@ -1869,6 +1869,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb, ...@@ -1869,6 +1869,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb,
#ifdef CONFIG_TLS_DEVICE #ifdef CONFIG_TLS_DEVICE
tail->decrypted != skb->decrypted || tail->decrypted != skb->decrypted ||
#endif #endif
!mptcp_skb_can_collapse(tail, skb) ||
thtail->doff != th->doff || thtail->doff != th->doff ||
memcmp(thtail + 1, th + 1, hdrlen - sizeof(*th))) memcmp(thtail + 1, th + 1, hdrlen - sizeof(*th)))
goto no_coalesce; goto no_coalesce;
......
...@@ -1298,7 +1298,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, ...@@ -1298,7 +1298,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
if (copy == 0) { if (copy == 0) {
u64 snd_una = READ_ONCE(msk->snd_una); u64 snd_una = READ_ONCE(msk->snd_una);
if (snd_una != msk->snd_nxt) { if (snd_una != msk->snd_nxt || tcp_write_queue_tail(ssk)) {
tcp_remove_empty_skb(ssk); tcp_remove_empty_skb(ssk);
return 0; return 0;
} }
...@@ -1306,11 +1306,6 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, ...@@ -1306,11 +1306,6 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
zero_window_probe = true; zero_window_probe = true;
data_seq = snd_una - 1; data_seq = snd_una - 1;
copy = 1; copy = 1;
/* all mptcp-level data is acked, no skbs should be present into the
* ssk write queue
*/
WARN_ON_ONCE(reuse_skb);
} }
copy = min_t(size_t, copy, info->limit - info->sent); copy = min_t(size_t, copy, info->limit - info->sent);
...@@ -1339,7 +1334,6 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, ...@@ -1339,7 +1334,6 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
if (reuse_skb) { if (reuse_skb) {
TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
mpext->data_len += copy; mpext->data_len += copy;
WARN_ON_ONCE(zero_window_probe);
goto out; goto out;
} }
...@@ -2354,6 +2348,26 @@ bool __mptcp_retransmit_pending_data(struct sock *sk) ...@@ -2354,6 +2348,26 @@ bool __mptcp_retransmit_pending_data(struct sock *sk)
#define MPTCP_CF_PUSH BIT(1) #define MPTCP_CF_PUSH BIT(1)
#define MPTCP_CF_FASTCLOSE BIT(2) #define MPTCP_CF_FASTCLOSE BIT(2)
/* be sure to send a reset only if the caller asked for it, also
* clean completely the subflow status when the subflow reaches
* TCP_CLOSE state
*/
static void __mptcp_subflow_disconnect(struct sock *ssk,
struct mptcp_subflow_context *subflow,
unsigned int flags)
{
if (((1 << ssk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ||
(flags & MPTCP_CF_FASTCLOSE)) {
/* The MPTCP code never wait on the subflow sockets, TCP-level
* disconnect should never fail
*/
WARN_ON_ONCE(tcp_disconnect(ssk, 0));
mptcp_subflow_ctx_reset(subflow);
} else {
tcp_shutdown(ssk, SEND_SHUTDOWN);
}
}
/* subflow sockets can be either outgoing (connect) or incoming /* subflow sockets can be either outgoing (connect) or incoming
* (accept). * (accept).
* *
...@@ -2391,7 +2405,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk, ...@@ -2391,7 +2405,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
lock_sock_nested(ssk, SINGLE_DEPTH_NESTING); lock_sock_nested(ssk, SINGLE_DEPTH_NESTING);
if ((flags & MPTCP_CF_FASTCLOSE) && !__mptcp_check_fallback(msk)) { if ((flags & MPTCP_CF_FASTCLOSE) && !__mptcp_check_fallback(msk)) {
/* be sure to force the tcp_disconnect() path, /* be sure to force the tcp_close path
* to generate the egress reset * to generate the egress reset
*/ */
ssk->sk_lingertime = 0; ssk->sk_lingertime = 0;
...@@ -2401,11 +2415,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk, ...@@ -2401,11 +2415,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
need_push = (flags & MPTCP_CF_PUSH) && __mptcp_retransmit_pending_data(sk); need_push = (flags & MPTCP_CF_PUSH) && __mptcp_retransmit_pending_data(sk);
if (!dispose_it) { if (!dispose_it) {
/* The MPTCP code never wait on the subflow sockets, TCP-level __mptcp_subflow_disconnect(ssk, subflow, flags);
* disconnect should never fail
*/
WARN_ON_ONCE(tcp_disconnect(ssk, 0));
mptcp_subflow_ctx_reset(subflow);
release_sock(ssk); release_sock(ssk);
goto out; goto out;
......
...@@ -1432,7 +1432,9 @@ chk_rst_nr() ...@@ -1432,7 +1432,9 @@ chk_rst_nr()
count=$(get_counter ${ns_tx} "MPTcpExtMPRstTx") count=$(get_counter ${ns_tx} "MPTcpExtMPRstTx")
if [ -z "$count" ]; then if [ -z "$count" ]; then
print_skip print_skip
elif [ $count -lt $rst_tx ]; then # accept more rst than expected except if we don't expect any
elif { [ $rst_tx -ne 0 ] && [ $count -lt $rst_tx ]; } ||
{ [ $rst_tx -eq 0 ] && [ $count -ne 0 ]; }; then
fail_test "got $count MP_RST[s] TX expected $rst_tx" fail_test "got $count MP_RST[s] TX expected $rst_tx"
else else
print_ok print_ok
...@@ -1442,7 +1444,9 @@ chk_rst_nr() ...@@ -1442,7 +1444,9 @@ chk_rst_nr()
count=$(get_counter ${ns_rx} "MPTcpExtMPRstRx") count=$(get_counter ${ns_rx} "MPTcpExtMPRstRx")
if [ -z "$count" ]; then if [ -z "$count" ]; then
print_skip print_skip
elif [ "$count" -lt "$rst_rx" ]; then # accept more rst than expected except if we don't expect any
elif { [ $rst_rx -ne 0 ] && [ $count -lt $rst_rx ]; } ||
{ [ $rst_rx -eq 0 ] && [ $count -ne 0 ]; }; then
fail_test "got $count MP_RST[s] RX expected $rst_rx" fail_test "got $count MP_RST[s] RX expected $rst_rx"
else else
print_ok print_ok
...@@ -2305,6 +2309,7 @@ remove_tests() ...@@ -2305,6 +2309,7 @@ remove_tests()
chk_join_nr 1 1 1 chk_join_nr 1 1 1
chk_rm_tx_nr 1 chk_rm_tx_nr 1
chk_rm_nr 1 1 chk_rm_nr 1 1
chk_rst_nr 0 0
fi fi
# multiple subflows, remove # multiple subflows, remove
...@@ -2317,6 +2322,7 @@ remove_tests() ...@@ -2317,6 +2322,7 @@ remove_tests()
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 2 2 2 chk_join_nr 2 2 2
chk_rm_nr 2 2 chk_rm_nr 2 2
chk_rst_nr 0 0
fi fi
# single address, remove # single address, remove
...@@ -2329,6 +2335,7 @@ remove_tests() ...@@ -2329,6 +2335,7 @@ remove_tests()
chk_join_nr 1 1 1 chk_join_nr 1 1 1
chk_add_nr 1 1 chk_add_nr 1 1
chk_rm_nr 1 1 invert chk_rm_nr 1 1 invert
chk_rst_nr 0 0
fi fi
# subflow and signal, remove # subflow and signal, remove
...@@ -2342,6 +2349,7 @@ remove_tests() ...@@ -2342,6 +2349,7 @@ remove_tests()
chk_join_nr 2 2 2 chk_join_nr 2 2 2
chk_add_nr 1 1 chk_add_nr 1 1
chk_rm_nr 1 1 chk_rm_nr 1 1
chk_rst_nr 0 0
fi fi
# subflows and signal, remove # subflows and signal, remove
...@@ -2356,6 +2364,7 @@ remove_tests() ...@@ -2356,6 +2364,7 @@ remove_tests()
chk_join_nr 3 3 3 chk_join_nr 3 3 3
chk_add_nr 1 1 chk_add_nr 1 1
chk_rm_nr 2 2 chk_rm_nr 2 2
chk_rst_nr 0 0
fi fi
# addresses remove # addresses remove
...@@ -2370,6 +2379,7 @@ remove_tests() ...@@ -2370,6 +2379,7 @@ remove_tests()
chk_join_nr 3 3 3 chk_join_nr 3 3 3
chk_add_nr 3 3 chk_add_nr 3 3
chk_rm_nr 3 3 invert chk_rm_nr 3 3 invert
chk_rst_nr 0 0
fi fi
# invalid addresses remove # invalid addresses remove
...@@ -2384,6 +2394,7 @@ remove_tests() ...@@ -2384,6 +2394,7 @@ remove_tests()
chk_join_nr 1 1 1 chk_join_nr 1 1 1
chk_add_nr 3 3 chk_add_nr 3 3
chk_rm_nr 3 1 invert chk_rm_nr 3 1 invert
chk_rst_nr 0 0
fi fi
# subflows and signal, flush # subflows and signal, flush
...@@ -2398,6 +2409,7 @@ remove_tests() ...@@ -2398,6 +2409,7 @@ remove_tests()
chk_join_nr 3 3 3 chk_join_nr 3 3 3
chk_add_nr 1 1 chk_add_nr 1 1
chk_rm_nr 1 3 invert simult chk_rm_nr 1 3 invert simult
chk_rst_nr 0 0
fi fi
# subflows flush # subflows flush
...@@ -2417,6 +2429,7 @@ remove_tests() ...@@ -2417,6 +2429,7 @@ remove_tests()
else else
chk_rm_nr 3 3 chk_rm_nr 3 3
fi fi
chk_rst_nr 0 0
fi fi
# addresses flush # addresses flush
...@@ -2431,6 +2444,7 @@ remove_tests() ...@@ -2431,6 +2444,7 @@ remove_tests()
chk_join_nr 3 3 3 chk_join_nr 3 3 3
chk_add_nr 3 3 chk_add_nr 3 3
chk_rm_nr 3 3 invert simult chk_rm_nr 3 3 invert simult
chk_rst_nr 0 0
fi fi
# invalid addresses flush # invalid addresses flush
...@@ -2445,6 +2459,7 @@ remove_tests() ...@@ -2445,6 +2459,7 @@ remove_tests()
chk_join_nr 1 1 1 chk_join_nr 1 1 1
chk_add_nr 3 3 chk_add_nr 3 3
chk_rm_nr 3 1 invert chk_rm_nr 3 1 invert
chk_rst_nr 0 0
fi fi
# remove id 0 subflow # remove id 0 subflow
...@@ -2456,6 +2471,7 @@ remove_tests() ...@@ -2456,6 +2471,7 @@ remove_tests()
run_tests $ns1 $ns2 10.0.1.1 run_tests $ns1 $ns2 10.0.1.1
chk_join_nr 1 1 1 chk_join_nr 1 1 1
chk_rm_nr 1 1 chk_rm_nr 1 1
chk_rst_nr 0 0
fi fi
# remove id 0 address # remove id 0 address
...@@ -2468,6 +2484,7 @@ remove_tests() ...@@ -2468,6 +2484,7 @@ remove_tests()
chk_join_nr 1 1 1 chk_join_nr 1 1 1
chk_add_nr 1 1 chk_add_nr 1 1
chk_rm_nr 1 1 invert chk_rm_nr 1 1 invert
chk_rst_nr 0 0 invert
fi fi
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment