Merge branch 'mptcp-misc-fixes-for-v7-1-rc4'

Matthieu Baerts says:

====================
mptcp: misc fixes for v7.1-rc4

Here are various unrelated fixes:

- Patch 1: avoid dropping partial packets. A previous version has been
  sent a few week ago. A fix for 5.10.

- Patches 2-3: stop ADD_ADDR timer when an ADD_ADDR can never been sent
  due to insufficient option space. A fix for v5.10.

- Patch 4: reset rcv_wnd_sent on disconnect, just in case the next
  connection falls back to TCP. A fix for 5.17.

- Patch 5: update window_clamp when SO_RCVBUF is set during the
  connection. A fix similar to a recent one on TCP side, for v6.6.

- Patch 6: avoid wrong time being displayed in the selftests when using
  uutils 0.8.0 which contains a regression with 'date +%3N'. It doesn't
  fix an issue in the kernel selftests, but having the fix is helpful
  for those using uutils 0.8.0.

Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
====================

Link: https://patch.msgid.link/20260515-net-mptcp-misc-fixes-7-1-rc4-v2-0-701e96419f2f@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
master
Paolo Abeni 2026-05-19 15:36:38 +02:00
commit edc502717b
6 changed files with 113 additions and 25 deletions

View File

@ -364,7 +364,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
spin_lock_bh(&msk->pm.lock);
if (!mptcp_pm_should_add_signal_addr(msk)) {
/* The cancel path (mptcp_pm_del_add_timer()) can race with this
* callback. Once cancel updates retrans_times to MAX, suppress further
* retransmissions here. If this callback acquires pm.lock first, one
* final transmit attempt is still possible.
*/
if (entry->retrans_times < ADD_ADDR_RETRANS_MAX &&
!mptcp_pm_should_add_signal_addr(msk)) {
pr_debug("retransmit ADD_ADDR id=%d\n", entry->addr.id);
mptcp_pm_announce_addr(msk, &entry->addr, false);
mptcp_pm_add_addr_send_ack(msk);
@ -414,8 +420,12 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk,
/* Note: entry might have been removed by another thread.
* We hold rcu_read_lock() to ensure it is not freed under us.
*/
if (stop_timer)
sk_stop_timer_sync(sk, &entry->add_timer);
if (stop_timer) {
if (check_id)
sk_stop_timer(sk, &entry->add_timer);
else
sk_stop_timer_sync(sk, &entry->add_timer);
}
rcu_read_unlock();
return entry;
@ -882,6 +892,7 @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb,
struct mptcp_addr_info *addr, bool *echo,
bool *drop_other_suboptions)
{
bool skip_add_addr = false;
int ret = false;
u8 add_addr;
u8 family;
@ -903,24 +914,49 @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb,
}
*echo = mptcp_pm_should_add_signal_echo(msk);
port = !!(*echo ? msk->pm.remote.port : msk->pm.local.port);
family = *echo ? msk->pm.remote.family : msk->pm.local.family;
if (remaining < mptcp_add_addr_len(family, *echo, port))
goto out_unlock;
if (*echo) {
*addr = msk->pm.remote;
add_addr = msk->pm.addr_signal & ~BIT(MPTCP_ADD_ADDR_ECHO);
port = !!msk->pm.remote.port;
family = msk->pm.remote.family;
} else {
*addr = msk->pm.local;
add_addr = msk->pm.addr_signal & ~BIT(MPTCP_ADD_ADDR_SIGNAL);
port = !!msk->pm.local.port;
family = msk->pm.local.family;
}
WRITE_ONCE(msk->pm.addr_signal, add_addr);
if (remaining < mptcp_add_addr_len(family, *echo, port)) {
struct net *net = sock_net((struct sock *)msk);
if (!*drop_other_suboptions)
goto out_unlock;
if (*echo) {
MPTCP_INC_STATS(net, MPTCP_MIB_ECHOADDTXDROP);
} else {
skip_add_addr = true;
MPTCP_INC_STATS(net, MPTCP_MIB_ADDADDRTXDROP);
}
goto drop_signal_mark;
}
ret = true;
drop_signal_mark:
WRITE_ONCE(msk->pm.addr_signal, add_addr);
out_unlock:
spin_unlock_bh(&msk->pm.lock);
/* On pure-ACK option-space exhaustion, stop retrying this ADD_ADDR:
* clear the signal bit, cancel the matching retransmission timer, and
* let the PM state machine progress.
*/
if (skip_add_addr) {
mptcp_pm_del_add_timer(msk, addr, true);
mptcp_pm_subflow_established(msk);
}
return ret;
}

View File

@ -397,12 +397,26 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
return false;
}
/* old data, keep it simple and drop the whole pkt, sender
* will retransmit as needed, if needed.
/* Completely old data? */
if (!after64(MPTCP_SKB_CB(skb)->end_seq, msk->ack_seq)) {
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
mptcp_drop(sk, skb);
return false;
}
/* Partial packet: map_seq < ack_seq < end_seq.
* Skip the already-acked bytes and enqueue the new data.
*/
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_DUPDATA);
mptcp_drop(sk, skb);
return false;
copy_len = MPTCP_SKB_CB(skb)->end_seq - msk->ack_seq;
MPTCP_SKB_CB(skb)->offset += msk->ack_seq - MPTCP_SKB_CB(skb)->map_seq;
MPTCP_SKB_CB(skb)->map_seq += msk->ack_seq -
MPTCP_SKB_CB(skb)->map_seq;
msk->bytes_received += copy_len;
WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len);
skb_set_owner_r(skb, sk);
__skb_queue_tail(&sk->sk_receive_queue, skb);
return true;
}
static void mptcp_stop_rtx_timer(struct sock *sk)
@ -3473,6 +3487,7 @@ static int mptcp_disconnect(struct sock *sk, int flags)
/* for fallback's sake */
WRITE_ONCE(msk->ack_seq, 0);
atomic64_set(&msk->rcv_wnd_sent, 0);
WRITE_ONCE(sk->sk_shutdown, 0);
sk_error_report(sk);

View File

@ -67,6 +67,12 @@ static int mptcp_get_int_option(struct mptcp_sock *msk, sockptr_t optval,
return 0;
}
static void __mptcp_subflow_set_rcvbuf(struct sock *ssk, int val)
{
WRITE_ONCE(ssk->sk_rcvbuf, val);
tcp_set_rcvbuf(ssk, val);
}
static void mptcp_sol_socket_sync_intval(struct mptcp_sock *msk, int optname, int val)
{
struct mptcp_subflow_context *subflow;
@ -100,7 +106,7 @@ static void mptcp_sol_socket_sync_intval(struct mptcp_sock *msk, int optname, in
case SO_RCVBUF:
case SO_RCVBUFFORCE:
ssk->sk_userlocks |= SOCK_RCVBUF_LOCK;
WRITE_ONCE(ssk->sk_rcvbuf, sk->sk_rcvbuf);
__mptcp_subflow_set_rcvbuf(ssk, sk->sk_rcvbuf);
break;
case SO_MARK:
if (READ_ONCE(ssk->sk_mark) != sk->sk_mark) {
@ -1560,7 +1566,7 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
mptcp_subflow_ctx(ssk)->cached_sndbuf = sk->sk_sndbuf;
}
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
WRITE_ONCE(ssk->sk_rcvbuf, sk->sk_rcvbuf);
__mptcp_subflow_set_rcvbuf(ssk, sk->sk_rcvbuf);
}
if (sock_flag(sk, SOCK_LINGER)) {

View File

@ -401,7 +401,7 @@ do_transfer()
mptcp_lib_wait_local_port_listen "${listener_ns}" "${port}"
local start
start=$(date +%s%3N)
start=$(date +%s%N)
ip netns exec ${connector_ns} \
./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \
$extra_args $connect_addr < "$cin" > "$cout" &
@ -423,7 +423,7 @@ do_transfer()
fi
local stop
stop=$(date +%s%3N)
stop=$(date +%s%N)
if $capture; then
sleep 1
@ -439,7 +439,7 @@ do_transfer()
fi
local duration
duration=$((stop-start))
duration=$(((stop-start) / 1000000))
printf "(duration %05sms) " "${duration}"
if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ] || [ ${timeout_pid} -ne 0 ]; then
mptcp_lib_pr_fail "client exit code $retc, server $rets"

View File

@ -1828,6 +1828,22 @@ chk_add_tx_nr()
fi
}
chk_add_drop_tx_nr()
{
local drop_tx_nr=$1
local count
print_check "add addr tx drop"
count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtAddAddrTxDrop")
if [ -z "$count" ]; then
print_skip
elif [ "$count" != "$drop_tx_nr" ]; then
fail_test "got $count ADD_ADDR drop[s] TX, expected $drop_tx_nr"
else
print_ok
fi
}
chk_rm_nr()
{
local rm_addr_nr=$1
@ -3278,6 +3294,21 @@ add_addr_ports_tests()
chk_mpc_endp_attempt ${retl} 1
fi
# first signal address drops, second one still progresses
if reset "signal addr list progresses after tx drop"; then
pm_nl_set_limits $ns1 0 2
pm_nl_set_limits $ns2 1 0
ip netns exec $ns1 sysctl -q net.ipv4.tcp_timestamps=1
ip netns exec $ns2 sysctl -q net.ipv4.tcp_timestamps=1
pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal port 10100
pm_nl_add_endpoint $ns1 dead:beef:3::1 flags signal
run_tests $ns1 $ns2 dead:beef:1::1
chk_add_drop_tx_nr 1
chk_add_tx_nr 1 1
chk_add_nr 1 1 0
fi
}
bind_tests()

View File

@ -28,7 +28,7 @@ declare -rx MPTCP_LIB_AF_INET6=10
MPTCP_LIB_SUBTESTS=()
MPTCP_LIB_SUBTESTS_DUPLICATED=0
MPTCP_LIB_SUBTEST_FLAKY=0
MPTCP_LIB_SUBTESTS_LAST_TS_MS=
MPTCP_LIB_SUBTESTS_LAST_TS_NS=
MPTCP_LIB_TEST_COUNTER=0
MPTCP_LIB_TEST_FORMAT="%02u %-50s"
MPTCP_LIB_IP_MPTCP=0
@ -236,7 +236,7 @@ mptcp_lib_kversion_ge() {
}
mptcp_lib_subtests_last_ts_reset() {
MPTCP_LIB_SUBTESTS_LAST_TS_MS="$(date +%s%3N)"
MPTCP_LIB_SUBTESTS_LAST_TS_NS="$(date +%s%N)"
}
mptcp_lib_subtests_last_ts_reset
@ -255,7 +255,7 @@ __mptcp_lib_result_check_duplicated() {
__mptcp_lib_result_add() {
local result="${1}"
local time="time="
local ts_prev_ms
local ts_prev_ns
shift
local id=$((${#MPTCP_LIB_SUBTESTS[@]} + 1))
@ -265,9 +265,9 @@ __mptcp_lib_result_add() {
# not to add two '#'
[[ "${*}" != *"#"* ]] && time="# ${time}"
ts_prev_ms="${MPTCP_LIB_SUBTESTS_LAST_TS_MS}"
ts_prev_ns="${MPTCP_LIB_SUBTESTS_LAST_TS_NS}"
mptcp_lib_subtests_last_ts_reset
time+="$((MPTCP_LIB_SUBTESTS_LAST_TS_MS - ts_prev_ms))ms"
time+="$(((MPTCP_LIB_SUBTESTS_LAST_TS_NS - ts_prev_ns) / 1000000))ms"
MPTCP_LIB_SUBTESTS+=("${result} ${id} - ${KSFT_TEST}: ${*} ${time}")
}