diff --git a/net/mptcp/options.c b/net/mptcp/options.c index b8318e030138..ce0de02f5a3a 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -93,7 +93,8 @@ static void mptcp_parse_option(const struct sk_buff *skb, * In other words, the only way for checksums not to be used * is if both hosts in their SYNs set A=0." */ - if (flags & MPTCP_CAP_CHECKSUM_REQD) + if ((flags & MPTCP_CAP_CHECKSUM_REQD) && + opsize < TCPOLEN_MPTCP_MPC_ACK_DATA) mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD; mp_opt->deny_join_id0 = !!(flags & MPTCP_CAP_DENY_JOIN_ID0); @@ -529,7 +530,7 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, return false; /* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */ - if (READ_ONCE(subflow->fully_established) || snd_data_fin_enable || + if (subflow->fully_established || snd_data_fin_enable || subflow->snd_isn != TCP_SKB_CB(skb)->seq || sk->sk_state != TCP_ESTABLISHED) return false; @@ -611,6 +612,7 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, ext->data_seq = data_fin_tx_seq; ext->subflow_seq = 0; ext->data_len = 1; + ext->csum = 0; } else if (ext->data_seq + ext->data_len == data_fin_tx_seq) { /* If there's an existing DSS mapping and it is the * final mapping, DATA_FIN consumes 1 additional byte of @@ -980,7 +982,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, /* here we can process OoO, in-window pkts, only in-sequence 4th ack * will make the subflow fully established */ - if (likely(READ_ONCE(subflow->fully_established))) { + if (likely(subflow->fully_established)) { /* on passive sockets, check for 3rd ack retransmission * note that msk is always set by subflow_syn_recv_sock() * for mp_join subflows diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 8b68868255c5..b0b71adefb8f 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -462,10 +462,10 @@ bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, add_entry->addr = *addr; add_entry->sock = msk; - add_entry->retrans_times = 0; timer_setup(&add_entry->timer, mptcp_pm_add_addr_timer, 0); reset_timer: + add_entry->retrans_times = 0; add_entry->timer_done = false; timeout = mptcp_adjust_add_addr_timeout(msk); if (timeout) diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index 424f1a7f9248..1a7750813235 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -1137,6 +1137,8 @@ static int mptcp_nl_remove_id_zero_address(struct net *net, while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) { struct sock *sk = (struct sock *)msk; struct mptcp_addr_info msk_local; + struct mptcp_addr_info anno_addr; + bool announced; if (list_empty(&msk->conn_list) || mptcp_pm_is_userspace(msk)) goto next; @@ -1146,7 +1148,13 @@ static int mptcp_nl_remove_id_zero_address(struct net *net, goto next; lock_sock(sk); + /* Drop a possibly pending ADD_ADDR for this address. */ + anno_addr = msk_local; + anno_addr.port = 0; + announced = mptcp_pm_announced_remove(msk, &anno_addr); spin_lock_bh(&msk->pm.lock); + if (announced) + msk->pm.add_addr_signaled--; mptcp_pm_remove_addr(msk, &list); mptcp_pm_rm_subflow(msk, &list); __mark_subflow_endp_available(msk, 0); diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index b94fbb483bf9..fab16d953dbf 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -69,6 +69,19 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk, } if (!addr_match && !id_match) { + unsigned int id; + + if (!entry->addr.id && needs_id) { + id = find_next_zero_bit(id_bitmap, + MPTCP_PM_MAX_ADDR_ID + 1, 1); + if (id > MPTCP_PM_MAX_ADDR_ID) { + ret = -ENOSPC; + goto append_err; + } + } else { + id = entry->addr.id; + } + /* Memory for the entry is allocated from the * sock option buffer. */ @@ -78,10 +91,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk, goto append_err; } - if (!e->addr.id && needs_id) - e->addr.id = find_next_zero_bit(id_bitmap, - MPTCP_PM_MAX_ADDR_ID + 1, - 1); + e->addr.id = id; list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list); msk->pm.local_addr_used++; ret = e->addr.id; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index e1f08f71cdb1..0098e2830931 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -95,6 +95,7 @@ bool __mptcp_try_fallback(struct mptcp_sock *msk, int fb_mib) msk->allow_subflows = false; set_bit(MPTCP_FALLBACK_DONE, &msk->flags); + clear_bit(MPTCP_RTX_ENABLED, &msk->flags); __MPTCP_INC_STATS(net, fb_mib); spin_unlock_bh(&msk->fallback_lock); return true; @@ -288,8 +289,8 @@ static void mptcp_prune_ofo_queue(struct sock *sk, */ static bool mptcp_can_ingest(const struct sock *sk) { - return unlikely(sk_rmem_alloc_get(sk) <= READ_ONCE(sk->sk_rcvbuf)) || - __mptcp_check_fallback(mptcp_sk(sk)); + return likely(sk_rmem_alloc_get(sk) <= READ_ONCE(sk->sk_rcvbuf)) || + __mptcp_check_fallback(mptcp_sk(sk)); } static bool mptcp_try_rmem_schedule(struct sock *sk, const struct sk_buff *skb) @@ -312,12 +313,6 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) u64 seq, end_seq, max_seq; struct sk_buff *skb1; - if (!mptcp_try_rmem_schedule(sk, skb)) { - MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); - mptcp_drop(sk, skb); - return; - } - seq = MPTCP_SKB_CB(skb)->map_seq; end_seq = MPTCP_SKB_CB(skb)->end_seq; max_seq = atomic64_read(&msk->rcv_wnd_sent); @@ -334,6 +329,12 @@ static void mptcp_data_queue_ofo(struct mptcp_sock *msk, struct sk_buff *skb) return; } + if (!mptcp_try_rmem_schedule(sk, skb)) { + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); + mptcp_drop(sk, skb); + return; + } + p = &msk->out_of_order_queue.rb_node; MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOQUEUE); if (RB_EMPTY_ROOT(&msk->out_of_order_queue)) { @@ -1084,13 +1085,14 @@ static bool mptcp_rtx_timer_pending(struct sock *sk) static void mptcp_reset_rtx_timer(struct sock *sk) { + struct mptcp_sock *msk = mptcp_sk(sk); unsigned long tout; - /* prevent rescheduling on close */ - if (unlikely(inet_sk_state_load(sk) == TCP_CLOSE)) + /* Prevent rescheduling on close and in case of fallback. */ + if (!test_bit(MPTCP_RTX_ENABLED, &msk->flags)) return; - tout = mptcp_sk(sk)->timer_ival; + tout = msk->timer_ival; sk_reset_timer(sk, &sk->mptcp_retransmit_timer, jiffies + tout); } @@ -3323,6 +3325,9 @@ void mptcp_set_state(struct sock *sk, int state) * transition from TCP_SYN_RECV to TCP_CLOSE_WAIT. */ break; + case TCP_CLOSE: + clear_bit(MPTCP_RTX_ENABLED, &mptcp_sk(sk)->flags); + fallthrough; default: if (oldstate == TCP_ESTABLISHED || oldstate == TCP_CLOSE_WAIT) MPTCP_DEC_STATS(sock_net(sk), MPTCP_MIB_CURRESTAB); @@ -3583,6 +3588,7 @@ static void mptcp_destroy_common(struct mptcp_sock *msk) static int mptcp_disconnect(struct sock *sk, int flags) { + struct inet_connection_sock *icsk = inet_csk(sk); struct mptcp_sock *msk = mptcp_sk(sk); /* We are on the fastopen error path. We can't call straight into the @@ -3595,8 +3601,13 @@ static int mptcp_disconnect(struct sock *sk, int flags) mptcp_check_listen_stop(sk); mptcp_set_state(sk, TCP_CLOSE); - mptcp_stop_rtx_timer(sk); - mptcp_stop_tout_timer(sk); + /* The later subflow close can not kick again the tout timer, + * as the msk is already in closed status. + */ + msk->timer_ival = icsk->icsk_rto_min; + sk_stop_timer_sync(sk, &sk->mptcp_retransmit_timer); + icsk->icsk_mtup.probe_timestamp = 0; + sk_stop_timer_sync(sk, &icsk->mptcp_tout_timer); mptcp_pm_connection_closed(msk); @@ -3875,7 +3886,7 @@ static void schedule_3rdack_retransmission(struct sock *ssk) struct tcp_sock *tp = tcp_sk(ssk); unsigned long timeout; - if (READ_ONCE(mptcp_subflow_ctx(ssk)->fully_established)) + if (mptcp_subflow_ctx(ssk)->fully_established) return; /* reschedule with a timeout above RTT, as we must look only for drop */ @@ -4141,6 +4152,7 @@ static int mptcp_connect(struct sock *sk, struct sockaddr_unsized *uaddr, if (IS_ERR(ssk)) return PTR_ERR(ssk); + set_bit(MPTCP_RTX_ENABLED, &msk->flags); mptcp_set_state(sk, TCP_SYN_SENT); subflow = mptcp_subflow_ctx(ssk); #ifdef CONFIG_TCP_MD5SIG @@ -4288,6 +4300,7 @@ static int mptcp_listen(struct socket *sock, int backlog) goto unlock; } + set_bit(MPTCP_RTX_ENABLED, &msk->flags); mptcp_set_state(sk, TCP_LISTEN); sock_set_flag(sk, SOCK_RCU_FREE); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 87ccb84e9927..2b4c27426477 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -116,6 +116,7 @@ #define MPTCP_WORK_RTX 1 #define MPTCP_FALLBACK_DONE 2 #define MPTCP_WORK_CLOSE_SUBFLOW 3 +#define MPTCP_RTX_ENABLED 4 /* MPTCP socket release cb flags */ #define MPTCP_PUSH_PENDING 1 diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index af81ad5e699d..01db7edce18a 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -2084,7 +2084,6 @@ static void subflow_ulp_clone(const struct request_sock *req, new_ctx->request_bkup = subflow_req->request_bkup; WRITE_ONCE(new_ctx->remote_id, subflow_req->remote_id); new_ctx->token = subflow_req->token; - new_ctx->thmac = subflow_req->thmac; /* the subflow req id is valid, fetched via subflow_check_req() * and subflow_token_join_request() diff --git a/net/mptcp/syncookies.c b/net/mptcp/syncookies.c index b5cac5701122..9474706641c1 100644 --- a/net/mptcp/syncookies.c +++ b/net/mptcp/syncookies.c @@ -26,7 +26,8 @@ struct join_entry { u32 local_nonce; u8 join_id; u8 local_id; - u8 backup; + u8 backup:1, + request_bkup:1; u8 valid; }; @@ -63,6 +64,7 @@ static void mptcp_join_store_state(struct join_entry *entry, entry->remote_nonce = subflow_req->remote_nonce; entry->local_nonce = subflow_req->local_nonce; entry->backup = subflow_req->backup; + entry->request_bkup = subflow_req->request_bkup; entry->join_id = subflow_req->remote_id; entry->local_id = subflow_req->local_id; entry->valid = 1; @@ -117,6 +119,7 @@ bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subfl subflow_req->remote_nonce = e->remote_nonce; subflow_req->local_nonce = e->local_nonce; subflow_req->backup = e->backup; + subflow_req->request_bkup = e->request_bkup; subflow_req->remote_id = e->join_id; subflow_req->local_id = e->local_id; subflow_req->token = e->token; diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c index ea4cb6c1bd5e..178d98d91fea 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -381,6 +381,9 @@ static int sock_connect_mptcp(const char * const remoteaddr, hints.ai_family = pf; + /* Keep the resolved address alive for the whole execution: it is + * used again when reconnecting, and will be released at exit time. + */ xgetaddrinfo(remoteaddr, port, &hints, &addr); for (a = addr; a; a = a->ai_next) { sock = socket(a->ai_family, a->ai_socktype, proto); @@ -421,7 +424,6 @@ static int sock_connect_mptcp(const char * const remoteaddr, sock = -1; } - freeaddrinfo(addr); if (sock != -1) SOCK_TEST_TCPULP(sock, proto); return sock; diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh index 5ef6033775c8..b9d14647f401 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_lib.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_lib.sh @@ -108,12 +108,14 @@ mptcp_lib_pr_info() { mptcp_lib_pr_nstat() { local ns="${1}" - local hist="/tmp/${ns}.out" + local cache="/tmp/${ns}.out" + local hist="/tmp/${ns}.nstat" - if [ -f "${hist}" ]; then - awk '$2 != 0 { print " "$0 }' "${hist}" + if [ -f "${cache}" ]; then + awk '$2 != 0 { print " "$0 }' "${cache}" else - ip netns exec "${ns}" nstat -as | grep Tcp + NSTAT_HISTORY="${hist}" ip netns exec "${ns}" nstat -s | + grep Tcp fi } @@ -414,19 +416,21 @@ mptcp_lib_nstat_get() { } # $1: ns, $2: MIB counter -# Get the counter from the history (mptcp_lib_nstat_{init,get}()) if available. -# If not, get the counter from nstat ignoring any history. +# Get the counter from the cache (mptcp_lib_nstat_{init,get}()) if available. +# If not, get the counter from nstat ignoring any cache, but using the history. mptcp_lib_get_counter() { local ns="${1}" local counter="${2}" - local hist="/tmp/${ns}.out" + local cache="/tmp/${ns}.out" + local hist="/tmp/${ns}.nstat" local count - if [[ -s "${hist}" && "${counter}" == *"Tcp"* ]]; then - count=$(awk "/^${counter} / {print \$2; exit}" "${hist}") + if [[ -s "${cache}" && "${counter}" == *"Tcp"* ]]; then + count=$(awk "/^${counter} / {print \$2; exit}" "${cache}") else - count=$(ip netns exec "${ns}" nstat -asz "${counter}" | - awk 'NR==1 {next} {print $2}') + count=$(NSTAT_HISTORY="${hist}" ip netns exec "${ns}" \ + nstat -sz "${counter}" | + awk 'NR==1 {next} {print $2}') fi if [ -z "${count}" ]; then mptcp_lib_fail_if_expected_feature "${counter} counter"