:p
atchew
Login
Up to this series, it was possible to add a "signal" MPTCP endpoint with an IPv6 address and a port, or to directly request to send an ADD_ADDR with a v6 address and a port, but the expected ADD_ADDR wasn't sent when TCP timestamps was used for the connection. In fact, such signalling option cannot be sent when TCP timestamps is used due to a lack of option space: the limit is at 40 bytes, and, with padding, TCP timestamps is taking 12 bytes, while an ADD_ADDR IPv6 + port is taking 30 bytes. The selected solution here is to simply drop the TCP timestamps option when such ADD_ADDR of 30 bytes needs to be sent. - Patches 1-3: small cleanups to avoid computing ADD/RM_ADDR twice. - Patches 4-7: the new feature, controlled by a new sysctl knob. - Patch 8: extra checks in the MPTCP Join selftests. - Patches 9-15: A bunch of refactoring: renamed confusing helpers and variables, and prevent future misused functions. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- Changes in v2: - Rebased: some diff caused by commit a02a765bd5c2 ("mptcp: change mptcp_established_options() to return opt_size") and commit bd34fa025726 ("mptcp: add-addr: always drop other suboptions") - Patch 4: Use READ_ONCE() to read sysctl data. (Eric) - Patches 5-6: Avoid passing local variables' addresses to mptcp_established_options not to force the compiler to use a stack canary in this hot function, even for non-MPTCP flows. (Eric) - Replaced previous patches 9-11 modifying selftests by a bunch of pm related refactoring: patches 9-15. - Link to v1: https://patch.msgid.link/20260601-net-next-mptcp-add-addr6-port-ts-v1-0-4fc25dfef62e@kernel.org --- Matthieu Baerts (NGI0) (15): mptcp: options: suboptions sizes can be negative mptcp: pm: avoid computing rm_addr size twice mptcp: pm: avoid computing add_addr size twice mptcp: introduce add_addr_v6_port_drop_ts sysctl knob tcp: allow mptcp to drop TS for some packets mptcp: pm: drop TCP TS with ADD_ADDRv6 + port selftests: mptcp: validate ADD_ADDRv6 + TS + port selftests: mptcp: always check sent/dropped ADD_ADDRs mptcp: pm: use for_each_subflow helper mptcp: pm: rename add_entry structure to add_addr mptcp: pm: uniform announced addresses helpers mptcp: pm: remove add_ prefix from timer mptcp: pm: make mptcp_pm_add_addr_send_ack static mptcp: pm: avoid using del_timer directly mptcp: options: rst: drop unused skb parameter Documentation/networking/mptcp-sysctl.rst | 13 ++ include/net/mptcp.h | 13 +- net/ipv4/tcp_output.c | 10 +- net/mptcp/ctrl.c | 18 ++- net/mptcp/options.c | 68 +++------ net/mptcp/pm.c | 191 ++++++++++++++---------- net/mptcp/pm_kernel.c | 22 +-- net/mptcp/pm_userspace.c | 6 +- net/mptcp/protocol.h | 48 ++---- net/mptcp/subflow.c | 4 +- tools/testing/selftests/net/mptcp/mptcp_join.sh | 83 +++++----- 11 files changed, 248 insertions(+), 228 deletions(-) --- base-commit: bfa3d89cc15c09f7d1581c834a5ed725189ec19f change-id: 20260601-net-next-mptcp-add-addr6-port-ts-40d8d74d8e20 Best regards, -- Matthieu Baerts (NGI0) <matttbe@kernel.org>
Use a signed int for the returned size, because when other options are dropped, the size can be negative, e.g. to send an echo ADD_ADDR with a v4 address, and no port. The behaviour is not changed, because it was working as expected with an overflow. But it is clearer like this, and it will help later on. Even if, for the moment, only the ADD_ADDR size can be negative in some cases, a signed int is now used for all mptcp_established_options_*() helpers, not to mismatch the type, and as a question of uniformity. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static void clear_3rdack_retransmission(struct sock *sk) } static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, - bool snd_data_fin_enable, - unsigned int *size, + bool snd_data_fin_enable, int *size, struct mptcp_out_options *opts) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); @@ -XXX,XX +XXX,XX @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, } static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb, - bool snd_data_fin_enable, - unsigned int *size, + bool snd_data_fin_enable, int *size, struct mptcp_out_options *opts) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); @@ -XXX,XX +XXX,XX @@ static u64 add_addr_generate_hmac(u64 key1, u64 key2, return get_unaligned_be64(&hmac[SHA256_DIGEST_SIZE - sizeof(u64)]); } -static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *skb, - unsigned int *size, +static bool mptcp_established_options_add_addr(struct sock *sk, + struct sk_buff *skb, int *size, unsigned int remaining, struct mptcp_out_options *opts) { @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff * return true; } -static bool mptcp_established_options_rm_addr(struct sock *sk, - unsigned int *size, +static bool mptcp_established_options_rm_addr(struct sock *sk, int *size, unsigned int remaining, struct mptcp_out_options *opts) { @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_rm_addr(struct sock *sk, return true; } -static bool mptcp_established_options_mp_prio(struct sock *sk, - unsigned int *size, +static bool mptcp_established_options_mp_prio(struct sock *sk, int *size, unsigned int remaining, struct mptcp_out_options *opts) { @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_mp_prio(struct sock *sk, } static noinline bool mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb, - unsigned int *size, + int *size, unsigned int remaining, struct mptcp_out_options *opts) { @@ -XXX,XX +XXX,XX @@ static noinline bool mptcp_established_options_rst(struct sock *sk, struct sk_bu return true; } -static bool mptcp_established_options_fastclose(struct sock *sk, - unsigned int *size, +static bool mptcp_established_options_fastclose(struct sock *sk, int *size, unsigned int remaining, struct mptcp_out_options *opts) { @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_fastclose(struct sock *sk, return true; } -static bool mptcp_established_options_mp_fail(struct sock *sk, - unsigned int *size, +static bool mptcp_established_options_mp_fail(struct sock *sk, int *size, unsigned int remaining, struct mptcp_out_options *opts) { @@ -XXX,XX +XXX,XX @@ int mptcp_established_options(struct sock *sk, struct sk_buff *skb, { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); - unsigned int opt_size = 0; int total_size = 0; bool snd_data_fin; bool ret = false; + int opt_size = 0; opts->suboptions = 0; @@ -XXX,XX +XXX,XX @@ int mptcp_established_options(struct sock *sk, struct sk_buff *skb, if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, opts)) ret = true; else if (mptcp_established_options_dss(sk, skb, snd_data_fin, &opt_size, opts)) { - unsigned int mp_fail_size; + int mp_fail_size; ret = true; if (mptcp_established_options_mp_fail(sk, &mp_fail_size, -- 2.53.0
mptcp_rm_addr_len helper was called twice: in mptcp_pm_rm_addr_signal, then just after in mptcp_established_options_rm_addr. Both to check the remaining space. The second call is not needed: if there is not enough space, mptcp_pm_rm_addr_signal will return false, and the caller, mptcp_established_options_rm_addr, will do the same without re-checking the size again. Instead, mptcp_pm_rm_addr_signal can directly set the size. While at it, move mptcp_rm_addr_len to pm.c, as it is now only used there, once. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 11 ++--------- net/mptcp/pm.c | 11 ++++++++++- net/mptcp/protocol.h | 10 +--------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_rm_addr(struct sock *sk, int *size, struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); struct mptcp_rm_list rm_list; - int i, len; + int i; if (!mptcp_pm_should_rm_signal(msk) || - !(mptcp_pm_rm_addr_signal(msk, remaining, &rm_list))) + !(mptcp_pm_rm_addr_signal(msk, remaining, &rm_list, size))) return false; - len = mptcp_rm_addr_len(&rm_list); - if (len < 0) - return false; - if (remaining < len) - return false; - - *size = len; opts->suboptions |= OPTION_MPTCP_RM_ADDR; opts->rm_list = rm_list; diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int opt_size, return ret; } +static int mptcp_rm_addr_len(const struct mptcp_rm_list *rm_list) +{ + if (rm_list->nr == 0 || rm_list->nr > MPTCP_RM_IDS_MAX) + return -EINVAL; + + return TCPOLEN_MPTCP_RM_ADDR_BASE + roundup(rm_list->nr - 1, 4) + 1; +} + bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, - struct mptcp_rm_list *rm_list) + struct mptcp_rm_list *rm_list, int *size) { int ret = false, len; u8 rm_addr; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, if (remaining < len) goto out_unlock; + *size = len; *rm_list = msk->pm.rm_list_tx; WRITE_ONCE(msk->pm.addr_signal, rm_addr); ret = true; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ static inline unsigned int mptcp_add_addr_len(int family, bool echo, bool port) return len; } -static inline int mptcp_rm_addr_len(const struct mptcp_rm_list *rm_list) -{ - if (rm_list->nr == 0 || rm_list->nr > MPTCP_RM_IDS_MAX) - return -EINVAL; - - return TCPOLEN_MPTCP_RM_ADDR_BASE + roundup(rm_list->nr - 1, 4) + 1; -} - bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int opt_size, unsigned int remaining, struct mptcp_addr_info *addr, bool *echo); bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, - struct mptcp_rm_list *rm_list); + struct mptcp_rm_list *rm_list, int *len); int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_pm_addr_entry *skc); -- 2.53.0
mptcp_add_addr_len helper was called twice: in mptcp_pm_add_addr_signal, then just after in mptcp_established_options_add_addr. Both to check the remaining space. The second call is not needed: if there is not enough space, mptcp_pm_add_addr_signal will return false, and the caller, mptcp_established_options_add_addr, will do the same without re-checking the size again. Instead, mptcp_pm_add_addr_signal can directly set the size. Note that the returned size can be negative when other suboptions are dropped, e.g. to send an echo ADD_ADDR with a v4 address, and no port. While at it: - move mptcp_add_addr_len to pm.c, as it is now only used from there - use 'int' in mptcp_add_addr_len for the size, instead of having a mix - use a bool for 'ret' in mptcp_pm_add_addr_signal Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 15 ++------------- net/mptcp/pm.c | 27 ++++++++++++++++++++++----- net/mptcp/protocol.h | 18 +----------------- 3 files changed, 25 insertions(+), 35 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_add_addr(struct sock *sk, { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); - unsigned int opt_size = *size; struct mptcp_addr_info addr; bool echo; - int len; /* add addr will strip the existing options, be sure to avoid breaking * MPC/MPJ handshakes @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_add_addr(struct sock *sk, if (!mptcp_pm_should_add_signal(msk) || (opts->suboptions & (OPTION_MPTCP_MPJ_ACK | OPTION_MPTCP_MPC_ACK)) || !skb || !skb_is_tcp_pure_ack(skb) || - !mptcp_pm_add_addr_signal(msk, opt_size, remaining, &addr, &echo)) + !mptcp_pm_add_addr_signal(msk, size, remaining, &addr, &echo)) return false; - remaining += opt_size; - - len = mptcp_add_addr_len(addr.family, echo, !!addr.port); - if (remaining < len) - return false; - - *size = len; pr_debug("drop other suboptions\n"); - opts->suboptions = 0; - *size -= opt_size; + opts->suboptions = OPTION_MPTCP_ADD_ADDR; opts->addr = addr; - opts->suboptions |= OPTION_MPTCP_ADD_ADDR; if (!echo) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRTX); opts->ahmac = add_addr_generate_hmac(READ_ONCE(msk->local_key), diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq) } } -bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int opt_size, - unsigned int remaining, +static int mptcp_add_addr_len(int family, bool echo, bool port) +{ + int len = TCPOLEN_MPTCP_ADD_ADDR_BASE; + + if (family == AF_INET6) + len = TCPOLEN_MPTCP_ADD_ADDR6_BASE; + if (!echo) + len += MPTCPOPT_THMAC_LEN; + /* account for 2 trailing 'nop' options */ + if (port) + len += TCPOLEN_MPTCP_PORT_LEN + TCPOLEN_MPTCP_PORT_ALIGN; + + return len; +} + +bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, int *size, int remaining, struct mptcp_addr_info *addr, bool *echo) { bool skip_add_addr = false; - int ret = false; + bool ret = false; u8 add_addr; + int len = 0; u8 family; bool port; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int opt_size, * plain dup-ack from TCP perspective. The other MPTCP-relevant info, * if any, will be carried by the 'original' TCP ack */ - remaining += opt_size; + len -= *size; *echo = mptcp_pm_should_add_signal_echo(msk); if (*echo) { @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int opt_size, family = msk->pm.local.family; } - if (remaining < mptcp_add_addr_len(family, *echo, port)) { + len += mptcp_add_addr_len(family, *echo, port); + if (len > remaining) { struct net *net = sock_net((struct sock *)msk); if (*echo) { @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int opt_size, } ret = true; + *size = len; drop_signal_mark: WRITE_ONCE(msk->pm.addr_signal, add_addr); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ static inline bool mptcp_pm_is_kernel(const struct mptcp_sock *msk) return READ_ONCE(msk->pm.pm_type) == MPTCP_PM_TYPE_KERNEL; } -static inline unsigned int mptcp_add_addr_len(int family, bool echo, bool port) -{ - u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE; - - if (family == AF_INET6) - len = TCPOLEN_MPTCP_ADD_ADDR6_BASE; - if (!echo) - len += MPTCPOPT_THMAC_LEN; - /* account for 2 trailing 'nop' options */ - if (port) - len += TCPOLEN_MPTCP_PORT_LEN + TCPOLEN_MPTCP_PORT_ALIGN; - - return len; -} - -bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int opt_size, - unsigned int remaining, +bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, int *size, int remaining, struct mptcp_addr_info *addr, bool *echo); bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, struct mptcp_rm_list *rm_list, int *len); -- 2.53.0
This sysctl is going to be used in the next commits to drop TCP timestamps option, to be able to send an ADD_ADDR with a v6 IP address and a port number. It is enabled by default. This knob is explicitly disabled in the MPTCP Join selftest, with the "signal addr list progresses after tx drop" subtest, to continue verifying the previous behaviour where the ADD_ADDR is not sent due to a lack of space. While at it, move syn_retrans_before_tcp_fallback down from struct mptcp_pernet, to avoid creating another 3 bytes hole. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- - v2: Use READ_ONCE() to read sysctl data. (Eric Dumazet) To: Jonathan Corbet <corbet@lwn.net> To: Shuah Khan <skhan@linuxfoundation.org> Cc: linux-doc@vger.kernel.org Cc: linux-kselftest@vger.kernel.org --- Documentation/networking/mptcp-sysctl.rst | 13 +++++++++++++ net/mptcp/ctrl.c | 18 +++++++++++++++++- net/mptcp/protocol.h | 1 + tools/testing/selftests/net/mptcp/mptcp_join.sh | 1 + 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/mptcp-sysctl.rst b/Documentation/networking/mptcp-sysctl.rst index XXXXXXX..XXXXXXX 100644 --- a/Documentation/networking/mptcp-sysctl.rst +++ b/Documentation/networking/mptcp-sysctl.rst @@ -XXX,XX +XXX,XX @@ add_addr_timeout - INTEGER (seconds) Default: 120 +add_addr_v6_port_drop_ts - BOOLEAN + Control whether preparing an ADD_ADDR with an IPv6 address and a port + should drop the TCP timestamps option to have enough option space to + send the signal. + + If there is not enough option space, and the TCP timestamps option + cannot be dropped, the signal cannot be sent. Note that dropping the TCP + timestamps option for one packet of the connection could disrupt some + middleboxes: even if it should be unlikely, they could drop the packet + or block the connection. This is a per-namespace sysctl. + + Default: 1 (enabled) + allow_join_initial_addr_port - BOOLEAN Allow peers to send join requests to the IP address and port number used by the initial subflow if the value is 1. This controls a flag that is diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -XXX,XX +XXX,XX @@ struct mptcp_pernet { unsigned int close_timeout; unsigned int stale_loss_cnt; atomic_t active_disable_times; - u8 syn_retrans_before_tcp_fallback; unsigned long active_disable_stamp; + u8 syn_retrans_before_tcp_fallback; u8 mptcp_enabled; u8 checksum_enabled; u8 allow_join_initial_addr_port; u8 pm_type; + u8 add_addr_v6_port_drop_ts; char scheduler[MPTCP_SCHED_NAME_MAX]; char path_manager[MPTCP_PM_NAME_MAX]; }; @@ -XXX,XX +XXX,XX @@ const char *mptcp_get_scheduler(const struct net *net) return mptcp_get_pernet(net)->scheduler; } +unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net) +{ + return READ_ONCE(mptcp_get_pernet(net)->add_addr_v6_port_drop_ts); +} + static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet) { pernet->mptcp_enabled = 1; @@ -XXX,XX +XXX,XX @@ static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet) pernet->pm_type = MPTCP_PM_TYPE_KERNEL; strscpy(pernet->scheduler, "default", sizeof(pernet->scheduler)); strscpy(pernet->path_manager, "kernel", sizeof(pernet->path_manager)); + pernet->add_addr_v6_port_drop_ts = 1; } #ifdef CONFIG_SYSCTL @@ -XXX,XX +XXX,XX @@ static struct ctl_table mptcp_sysctl_table[] = { .mode = 0444, .proc_handler = proc_available_path_managers, }, + { + .procname = "add_addr_v6_port_drop_ts", + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE + }, }; static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) @@ -XXX,XX +XXX,XX @@ static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) table[10].data = &pernet->syn_retrans_before_tcp_fallback; table[11].data = &pernet->path_manager; /* table[12] is for available_path_managers which is read-only info */ + table[13].data = &pernet->add_addr_v6_port_drop_ts; hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table, ARRAY_SIZE(mptcp_sysctl_table)); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ unsigned int mptcp_close_timeout(const struct sock *sk); int mptcp_get_pm_type(const struct net *net); const char *mptcp_get_path_manager(const struct net *net); const char *mptcp_get_scheduler(const struct net *net); +unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net); void mptcp_active_disable(struct sock *sk); bool mptcp_active_should_disable(struct sock *ssk); diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index XXXXXXX..XXXXXXX 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -XXX,XX +XXX,XX @@ add_addr_ports_tests() 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.mptcp.add_addr_v6_port_drop_ts=0 2>/dev/null || true ip netns exec $ns1 sysctl -q net.ipv4.tcp_timestamps=1 ip netns exec $ns2 sysctl -q net.ipv4.tcp_timestamps=1 -- 2.53.0
With TCP-timestamps (padded) taking 12 bytes and ADD_ADDR IPv6 + port taking 30 bytes, the 40-byte limit for the TCP options is reached. In this case, it is then not possible to send the address signal. The idea is to let MPTCP dropping the TCP-timestamps option for some specific packets, to be able to send some specific pure ACK carrying >28 bytes of MPTCP options, like with this specific ADD_ADDR. A new parameter is passed from tcp_established_options to the MPTCP side to indicate if the TCP TS option is used, and if it should be dropped. The next commit implements the part on MPTCP side, but split into two patches to help TCP maintainers to identify the modifications on TCP side. This feature will be controlled by a new add_addr_v6_port_drop_ts MPTCP sysctl knob. It is important to keep in mind that dropping the TCP timestamps option for one packet of the connection could eventually disrupt some middleboxes: even if it should be unlikely, they could drop the packet or even block the connection. That's why this new feature will be controlled by a sysctl knob. Note that it would be technically possible to squeeze both options into the header if the ADD_ADDR is first written, and then the TCP timestamps without the NOPs preceding it. But this means more modifications on TCP side, plus some middleboxes could still be disrupted by that. In this implementation, an unused bit is used in mptcp_out_options structure to avoid passing an address to a local variable. Reading and setting it needs CONFIG_MPTCP, so the whole block now has this #if condition: mptcp_established_options() is then no longer used without CONFIG_MPTCP. About alternatives, instead of passing a new boolean (has_ts), another option would be to pass the whole option structure (opts), but 'struct tcp_out_options' is currently defined in tcp_output.c, and it would need to be exported. Plus that means the removal of the TCP TS option would be done on the MPTCP side, and not here on the TCP side. It feels clearer to remove other TCP options from the TCP side, than hiding that from the MPTCP side. Yet an other alternative would be to pass the size already taken by the other TCP options, and have a way to drop them all when needed. But this feels better to target only the timestamps option where dropping it should be safe, even if it is currently the only option that would be set before MPTCP, when MPTCP is used. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- - v2: Avoid passing local variables' addresses to mptcp_established_options not to force the compiler to use a stack canary in this hot function, even for non-MPTCP flows. (Eric Dumazet) To: Neal Cardwell <ncardwell@google.com> To: Kuniyuki Iwashima <kuniyu@google.com> --- include/net/mptcp.h | 13 +++---------- net/ipv4/tcp_output.c | 10 +++++++++- net/mptcp/options.c | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -XXX,XX +XXX,XX @@ struct mptcp_out_options { u8 reset_reason:4, reset_transient:1, csum_reqd:1, - allow_join_id0:1; + allow_join_id0:1, + drop_ts:1; union { struct { u64 sndr_key; @@ -XXX,XX +XXX,XX @@ bool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb, bool mptcp_synack_options(const struct request_sock *req, unsigned int *size, struct mptcp_out_options *opts); int mptcp_established_options(struct sock *sk, struct sk_buff *skb, - unsigned int remaining, + unsigned int remaining, bool has_ts, struct mptcp_out_options *opts); bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb); @@ -XXX,XX +XXX,XX @@ static inline bool mptcp_synack_options(const struct request_sock *req, return false; } -static inline int mptcp_established_options(struct sock *sk, - struct sk_buff *skb, - unsigned int remaining, - struct mptcp_out_options *opts) -{ - return -1; -} - static inline bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index XXXXXXX..XXXXXXX 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -XXX,XX +XXX,XX @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb size += TCPOLEN_TSTAMP_ALIGNED; } +#if IS_ENABLED(CONFIG_MPTCP) /* MPTCP options have precedence over SACK for the limited TCP * option space because a MPTCP connection would be forced to * fall back to regular TCP if a required multipath option is @@ -XXX,XX +XXX,XX @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb */ if (sk_is_mptcp(sk)) { unsigned int remaining = MAX_TCP_OPTION_SPACE - size; + bool has_ts = opts->options & OPTION_TS; int opt_size; - opt_size = mptcp_established_options(sk, skb, remaining, + opts->mptcp.drop_ts = 0; + + opt_size = mptcp_established_options(sk, skb, remaining, has_ts, &opts->mptcp); if (opt_size >= 0) { opts->options |= OPTION_MPTCP; size += opt_size; + + if (opts->mptcp.drop_ts) + opts->options &= ~OPTION_TS; } } +#endif eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack; if (unlikely(eff_sacks)) { diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_mp_fail(struct sock *sk, int *size, } int mptcp_established_options(struct sock *sk, struct sk_buff *skb, - unsigned int remaining, + unsigned int remaining, bool has_ts, struct mptcp_out_options *opts) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); -- 2.53.0
With TCP-timestamps (padded) taking 12 bytes and ADD_ADDR IPv6 + port taking 30 bytes, the 40-byte limit for the TCP options is reached. In this case, it is then not possible to send the signal. To be able to send this ADD_ADDR, the TCP timestamps option can now be dropped. This is done, when needed by setting the *drop_ts parameter from mptcp_established_options. This feature is controlled by a new net.mptcp.add_addr_v6_port_drop_ts sysctl knob, enabled by default. It is important to keep in mind that dropping the TCP timestamps option for one packet of the connection could eventually disrupt some middleboxes: even if it should be unlikely, they could drop the packet or even block the connection. That's why this new feature can be controlled by a sysctl knob. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/448 Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 9 +++++++-- net/mptcp/pm.c | 13 ++++++++++++- net/mptcp/protocol.h | 3 ++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static u64 add_addr_generate_hmac(u64 key1, u64 key2, static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *skb, int *size, unsigned int remaining, + bool has_ts, struct mptcp_out_options *opts) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); struct mptcp_addr_info addr; + bool drop_ts = has_ts; bool echo; /* add addr will strip the existing options, be sure to avoid breaking @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_add_addr(struct sock *sk, if (!mptcp_pm_should_add_signal(msk) || (opts->suboptions & (OPTION_MPTCP_MPJ_ACK | OPTION_MPTCP_MPC_ACK)) || !skb || !skb_is_tcp_pure_ack(skb) || - !mptcp_pm_add_addr_signal(msk, size, remaining, &addr, &echo)) + !mptcp_pm_add_addr_signal(msk, size, remaining, &addr, &echo, + &drop_ts)) return false; pr_debug("drop other suboptions\n"); opts->suboptions = OPTION_MPTCP_ADD_ADDR; + opts->drop_ts = drop_ts; opts->addr = addr; if (!echo) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRTX); @@ -XXX,XX +XXX,XX @@ int mptcp_established_options(struct sock *sk, struct sk_buff *skb, total_size += opt_size; remaining -= opt_size; - if (mptcp_established_options_add_addr(sk, skb, &opt_size, remaining, opts)) { + if (mptcp_established_options_add_addr(sk, skb, &opt_size, remaining, + has_ts, opts)) { total_size += opt_size; remaining -= opt_size; ret = true; diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ static int mptcp_add_addr_len(int family, bool echo, bool port) } bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, int *size, int remaining, - struct mptcp_addr_info *addr, bool *echo) + struct mptcp_addr_info *addr, bool *echo, + bool *drop_ts) { bool skip_add_addr = false; bool ret = false; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, int *size, int remaining, if (len > remaining) { struct net *net = sock_net((struct sock *)msk); + if (*drop_ts && mptcp_add_addr_v6_port_drop_ts(net)) { + /* OK without TCP Timestamps? */ + len -= TCPOLEN_TSTAMP_ALIGNED; + if (len <= remaining) + goto enough_space; + } + if (*echo) { MPTCP_INC_STATS(net, MPTCP_MIB_ECHOADDTXDROP); } else { @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, int *size, int remaining, goto drop_signal_mark; } + *drop_ts = false; + +enough_space: ret = true; *size = len; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ static inline bool mptcp_pm_is_kernel(const struct mptcp_sock *msk) } bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, int *size, int remaining, - struct mptcp_addr_info *addr, bool *echo); + struct mptcp_addr_info *addr, bool *echo, + bool *drop_ts); bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, struct mptcp_rm_list *rm_list, int *len); int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); -- 2.53.0
This validates the feature added by parent commit, where it is now possible to send an ADD_ADDR with a v6 IP address and a port number, while the connection is using TCP Timestamps. This test is simply a copy of the previous one: "signal address with port", but using IPv6 addresses. This test is only executed if the add_addr_v6_port_drop_ts sysctl knob is available. If not, it means the kernel doesn't support this feature. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- To: Shuah Khan <shuah@kernel.org> Cc: linux-kselftest@vger.kernel.org --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index XXXXXXX..XXXXXXX 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -XXX,XX +XXX,XX @@ add_addr_ports_tests() chk_add_nr 1 1 1 fi + # signal address v6 with port + if reset "signal address v6 with port" && + continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/add_addr_v6_port_drop_ts'; then + pm_nl_set_limits $ns1 0 1 + pm_nl_set_limits $ns2 1 1 + pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal port 10100 + run_tests $ns1 $ns2 dead:beef:1::1 + chk_join_nr 1 1 1 + chk_add_nr 1 1 1 + fi + # subflow and signal with port if reset "subflow and signal with port"; then pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 -- 2.53.0
Before, they were only checked on demand, but it seems better to check them each time received ADD_ADDRs are checked. Errors are only reported when the counter exists, and the value is not the expected one. This is similar to what is done in chk_join_nr: it reduces the output, and avoids a lot of 'skip' when validating older kernels. Also here, some tests need to adapt the default expected counters, e.g. when ADD_ADDR echo are dropped on the reception side, or it is not possible to send an ADD_ADDR due to the limited option space. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- To: Shuah Khan <shuah@kernel.org> Cc: linux-kselftest@vger.kernel.org --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 71 ++++++++++--------------- 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index XXXXXXX..XXXXXXX 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -XXX,XX +XXX,XX @@ unset fb_mpc_data unset fb_md5_sig unset fb_dss +unset add_addr_tx_nr +unset add_addr_echo_tx_nr +unset add_addr_drop_tx_nr + # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" CBPF_MPTCP_SUBOPTION_ADD_ADDR="14, @@ -XXX,XX +XXX,XX @@ chk_add_nr() local ack_nr=$port_nr local mis_syn_nr=0 local mis_ack_nr=0 + local add_tx_nr=${add_addr_tx_nr:-${add_nr}} + local echo_tx_nr=${add_addr_echo_tx_nr:-${echo_nr}} + local drop_tx_nr=${add_addr_drop_tx_nr:-0} local ns_tx=$ns1 local ns_rx=$ns2 local tx="" @@ -XXX,XX +XXX,XX @@ chk_add_nr() print_ok fi fi -} -chk_add_tx_nr() -{ - local add_tx_nr=$1 - local echo_tx_nr=$2 - local count - - print_check "add addr tx" - count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtAddAddrTx") - if [ -z "$count" ]; then - print_skip + count=$(mptcp_lib_get_counter ${ns_tx} "MPTcpExtAddAddrTx") # Tolerate more ADD_ADDR then expected (if any), due to retransmissions - elif [ "$count" != "$add_tx_nr" ] && - { [ "$add_tx_nr" -eq 0 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + if [ -n "$count" ] && [ "$count" != "$add_tx_nr" ] && + { [ "$add_tx_nr" -eq 0 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + print_check "add addr tx" fail_test "got $count ADD_ADDR[s] TX, expected $add_tx_nr" - else - print_ok fi - print_check "add addr echo tx" - count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtEchoAddTx") - if [ -z "$count" ]; then - print_skip - elif [ "$count" != "$echo_tx_nr" ]; then + count=$(mptcp_lib_get_counter ${ns_rx} "MPTcpExtEchoAddTx") + if [ -n "$count" ] && [ "$count" != "$echo_tx_nr" ]; then + print_check "add addr echo tx" fail_test "got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" - else - print_ok 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 + count=$(mptcp_lib_get_counter ${ns_tx} "MPTcpExtAddAddrTxDrop") + if [ -n "$count" ] && [ "$count" != "$drop_tx_nr" ]; then + print_check "add addr tx drop" fail_test "got $count ADD_ADDR drop[s] TX, expected $drop_tx_nr" - else - print_ok fi } @@ -XXX,XX +XXX,XX @@ signal_address_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 - chk_add_tx_nr 1 1 chk_add_nr 1 1 fi @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() speed=slow \ run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 1 1 1 - chk_add_tx_nr 4 4 - chk_add_nr 4 0 + add_addr_echo_tx_nr=4 \ + chk_add_nr 4 0 fi # add_addr timeout IPv6 @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() speed=slow \ run_tests $ns1 $ns2 dead:beef:1::1 chk_join_nr 1 1 1 - chk_add_nr 4 0 + add_addr_echo_tx_nr=4 \ + chk_add_nr 4 0 fi # signal addresses timeout @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() speed=10 \ run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 - chk_add_nr 8 0 + add_addr_echo_tx_nr=8 \ + chk_add_nr 8 0 fi # signal invalid addresses timeout @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() run_tests $ns1 $ns2 10.0.1.1 join_syn_tx=2 \ chk_join_nr 1 1 1 - chk_add_nr 8 0 + add_addr_echo_tx_nr=7 \ + chk_add_nr 8 0 fi } @@ -XXX,XX +XXX,XX @@ add_addr_ports_tests() 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 + add_addr_drop_tx_nr=1 \ + chk_add_nr 1 1 0 fi } -- 2.53.0
Similar to most places in the MPTCP code. So instead of passing the subflow list and use list_for_each_entry(subflow, list, node), pass the msk and use mptcp_for_each_subflow(msk, subflow). That's clearer and more uniform with the rest. While at it, add 'pm_' prefix for the exported one to easily identify the origin. Plus replace 'lookup' by 'has', because a bool is returned. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 6 +++--- net/mptcp/pm_kernel.c | 12 ++++++------ net/mptcp/pm_userspace.c | 2 +- net/mptcp/protocol.h | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_pm_is_init_remote_addr(struct mptcp_sock *msk, return mptcp_addresses_equal(&mpc_remote, remote, remote->port); } -bool mptcp_lookup_subflow_by_saddr(const struct list_head *list, - const struct mptcp_addr_info *saddr) +bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, + const struct mptcp_addr_info *saddr) { struct mptcp_subflow_context *subflow; struct mptcp_addr_info cur; struct sock_common *skc; - list_for_each_entry(subflow, list, node) { + mptcp_for_each_subflow(msk, subflow) { skc = (struct sock_common *)mptcp_subflow_tcp_sock(subflow); mptcp_local_address(skc, &cur); diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -XXX,XX +XXX,XX @@ u8 mptcp_pm_get_limit_extra_subflows(const struct mptcp_sock *msk) } EXPORT_SYMBOL_GPL(mptcp_pm_get_limit_extra_subflows); -static bool lookup_subflow_by_daddr(const struct list_head *list, - const struct mptcp_addr_info *daddr) +static bool has_subflow_daddr(const struct mptcp_sock *msk, + const struct mptcp_addr_info *daddr) { struct mptcp_subflow_context *subflow; struct mptcp_addr_info cur; - list_for_each_entry(subflow, list, node) { + mptcp_for_each_subflow(msk, subflow) { struct sock *ssk = mptcp_subflow_tcp_sock(subflow); if (!((1 << inet_sk_state_load(ssk)) & @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk) mptcp_pm_addr_send_ack(msk); mptcp_mpc_endpoint_setup(msk); - if (lookup_subflow_by_daddr(&msk->conn_list, &remote)) + if (has_subflow_daddr(msk, &remote)) return; /* pick id 0 port, if none is provided the remote address */ @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, goto next; lock_sock(sk); - remove_subflow = mptcp_lookup_subflow_by_saddr(&msk->conn_list, addr); + remove_subflow = mptcp_pm_has_subflow_saddr(msk, addr); mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk, entry = list_prepare_entry(entry, rm_list, list); list_for_each_entry_continue(entry, rm_list, list) { - if (mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) + if (mptcp_pm_has_subflow_saddr(msk, &entry->addr)) slist.ids[slist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -XXX,XX +XXX,XX @@ void mptcp_pm_remove_addr_entry(struct mptcp_sock *msk, /* only delete if either announced or matching a subflow */ if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) anno_nr++; - else if (!mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) + else if (!mptcp_pm_has_subflow_saddr(msk, &entry->addr)) return; alist.ids[alist.nr++] = entry->addr.id; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk); struct mptcp_pm_add_entry * mptcp_pm_del_add_timer(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool check_id); -bool mptcp_lookup_subflow_by_saddr(const struct list_head *list, - const struct mptcp_addr_info *saddr); +bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, + const struct mptcp_addr_info *saddr); bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local, -- 2.53.0
Using only the 'add' prefix is confusing: does it refer to a generic added entry or address, or specifically to ADD_ADDRs. Using add_addr removes this confusion. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 22 +++++++++++----------- net/mptcp/protocol.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ #define ADD_ADDR_RETRANS_MAX 3 -struct mptcp_pm_add_entry { +struct mptcp_pm_add_addr { struct list_head list; struct mptcp_addr_info addr; u8 retrans_times; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, return false; } -static struct mptcp_pm_add_entry * +static struct mptcp_pm_add_addr * mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { - struct mptcp_pm_add_entry *entry; + struct mptcp_pm_add_addr *entry; lockdep_assert_held(&msk->pm.lock); @@ -XXX,XX +XXX,XX @@ mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { - struct mptcp_pm_add_entry *entry; + struct mptcp_pm_add_addr *entry; bool ret; entry = mptcp_pm_del_add_timer(msk, addr, false); @@ -XXX,XX +XXX,XX @@ bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk) { - struct mptcp_pm_add_entry *entry; + struct mptcp_pm_add_addr *entry; struct mptcp_addr_info saddr; bool ret = false; @@ -XXX,XX +XXX,XX @@ static unsigned int mptcp_adjust_add_addr_timeout(struct mptcp_sock *msk) static void mptcp_pm_add_timer(struct timer_list *timer) { - struct mptcp_pm_add_entry *entry = timer_container_of(entry, timer, - add_timer); + struct mptcp_pm_add_addr *entry = timer_container_of(entry, timer, + add_timer); struct mptcp_sock *msk = entry->sock; struct sock *sk = (struct sock *)msk; unsigned int timeout = 0; @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_timer(struct timer_list *timer) sock_put(sk); } -struct mptcp_pm_add_entry * +struct mptcp_pm_add_addr * mptcp_pm_del_add_timer(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool check_id) { - struct mptcp_pm_add_entry *entry; struct sock *sk = (struct sock *)msk; + struct mptcp_pm_add_addr *entry; bool stop_timer = false; rcu_read_lock(); @@ -XXX,XX +XXX,XX @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { - struct mptcp_pm_add_entry *add_entry = NULL; + struct mptcp_pm_add_addr *add_entry = NULL; struct sock *sk = (struct sock *)msk; unsigned int timeout; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, static void mptcp_pm_free_anno_list(struct mptcp_sock *msk) { - struct mptcp_pm_add_entry *entry, *tmp; + struct mptcp_pm_add_addr *entry, *tmp; struct sock *sk = (struct sock *)msk; LIST_HEAD(free_list); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk, bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk); -struct mptcp_pm_add_entry * +struct mptcp_pm_add_addr * mptcp_pm_del_add_timer(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool check_id); bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, -- 2.53.0
Similar to the previous commit, only using the 'add' or 'anno' prefixes is confusing -- generally associated to the action of adding something, or the Latin name for "year" -- and lack of uniformity. This has been causing issues in the past, e.g. del_add_timer seemed to suggest the goal is to delete a previously added timer. Instead, use the mptcp_pm_announced_ prefix. While at it, slightly improves some helpers: - mptcp_lookup_anno_list_by_saddr: no need to specify what is used to do the lookup: mptcp_pm_announced_lookup. - mptcp_pm_sport_in_anno_list: it doesn't just compare the port, but the whole address linked to the sublow: mptcp_pm_announced_has_ssk. - mptcp_pm_alloc_anno_list: it allocates one item of the list, not a whole list: mptcp_pm_announced_alloc. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 2 +- net/mptcp/pm.c | 35 +++++++++++++++++------------------ net/mptcp/pm_kernel.c | 10 +++++----- net/mptcp/pm_userspace.c | 4 ++-- net/mptcp/protocol.h | 12 ++++++------ net/mptcp/subflow.c | 4 ++-- 6 files changed, 33 insertions(+), 34 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR); } else { mptcp_pm_add_addr_echoed(msk, &mp_opt.addr); - mptcp_pm_del_add_timer(msk, &mp_opt.addr, true); + mptcp_pm_announced_del_timer(msk, &mp_opt.addr, true); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD); } diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, } static struct mptcp_pm_add_addr * -mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, - const struct mptcp_addr_info *addr) +mptcp_pm_announced_lookup(const struct mptcp_sock *msk, + const struct mptcp_addr_info *addr) { struct mptcp_pm_add_addr *entry; @@ -XXX,XX +XXX,XX @@ mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, return NULL; } -bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr) +bool mptcp_pm_announced_remove(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr) { struct mptcp_pm_add_addr *entry; bool ret; - entry = mptcp_pm_del_add_timer(msk, addr, false); + entry = mptcp_pm_announced_del_timer(msk, addr, false); ret = entry; kfree_rcu(entry, rcu); return ret; } -bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk) +bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *ssk) { struct mptcp_pm_add_addr *entry; struct mptcp_addr_info saddr; bool ret = false; - mptcp_local_address((struct sock_common *)sk, &saddr); + mptcp_local_address((struct sock_common *)ssk, &saddr); spin_lock_bh(&msk->pm.lock); list_for_each_entry(entry, &msk->pm.anno_list, list) { @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_timer(struct timer_list *timer) spin_lock_bh(&msk->pm.lock); - /* The cancel path (mptcp_pm_del_add_timer()) can race with this + /* The cancel path (mptcp_pm_announced_del_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. @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_timer(struct timer_list *timer) } struct mptcp_pm_add_addr * -mptcp_pm_del_add_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id) +mptcp_pm_announced_del_timer(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr, bool check_id) { struct sock *sk = (struct sock *)msk; struct mptcp_pm_add_addr *entry; @@ -XXX,XX +XXX,XX @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, rcu_read_lock(); spin_lock_bh(&msk->pm.lock); - entry = mptcp_lookup_anno_list_by_saddr(msk, addr); + entry = mptcp_pm_announced_lookup(msk, addr); if (entry && (!check_id || entry->addr.id == addr->id)) { entry->retrans_times = ADD_ADDR_RETRANS_MAX; stop_timer = true; @@ -XXX,XX +XXX,XX @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, return entry; } -bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, +bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { struct mptcp_pm_add_addr *add_entry = NULL; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, lockdep_assert_held(&msk->pm.lock); - add_entry = mptcp_lookup_anno_list_by_saddr(msk, addr); - + add_entry = mptcp_pm_announced_lookup(msk, addr); if (add_entry) { if (WARN_ON_ONCE(mptcp_pm_is_kernel(msk))) return false; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, return true; } -static void mptcp_pm_free_anno_list(struct mptcp_sock *msk) +static void mptcp_pm_free_announced_list(struct mptcp_sock *msk) { struct mptcp_pm_add_addr *entry, *tmp; struct sock *sk = (struct sock *)msk; @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, spin_lock_bh(&pm->lock); - if (mptcp_lookup_anno_list_by_saddr(msk, addr) && READ_ONCE(pm->work_pending)) + if (mptcp_pm_announced_lookup(msk, addr) && READ_ONCE(pm->work_pending)) mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED); spin_unlock_bh(&pm->lock); @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, int *size, int remaining, * let the PM state machine progress. */ if (skip_add_addr) { - mptcp_pm_del_add_timer(msk, addr, true); + mptcp_pm_announced_del_timer(msk, addr, true); mptcp_pm_subflow_established(msk); } return ret; @@ -XXX,XX +XXX,XX @@ void mptcp_pm_worker(struct mptcp_sock *msk) void mptcp_pm_destroy(struct mptcp_sock *msk) { - mptcp_pm_free_anno_list(msk); + mptcp_pm_free_announced_list(msk); if (mptcp_pm_is_userspace(msk)) mptcp_userspace_pm_free_local_addr_list(msk); diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) /* If the alloc fails, we are on memory pressure, not worth * continuing, and trying to create subflows. */ - if (!mptcp_pm_alloc_anno_list(msk, &local.addr)) + if (!mptcp_pm_announced_alloc(msk, &local.addr)) return; __clear_bit(endp_id, msk->pm.id_avail_bitmap); @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info) return ret; } -static void mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, +static void mptcp_pm_remove_announced(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool force) { @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, list.ids[list.nr++] = mptcp_endp_get_local_id(msk, addr); - announced = mptcp_remove_anno_list_by_saddr(msk, addr); + announced = mptcp_pm_announced_remove(msk, addr); if (announced || force) { spin_lock_bh(&msk->pm.lock); if (announced) @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, lock_sock(sk); remove_subflow = mptcp_pm_has_subflow_saddr(msk, addr); - mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && + mptcp_pm_remove_announced(msk, addr, remove_subflow && !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); list.ids[0] = mptcp_endp_get_local_id(msk, addr); @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk, if (mptcp_pm_has_subflow_saddr(msk, &entry->addr)) slist.ids[slist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); - if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) + if (mptcp_pm_announced_remove(msk, &entry->addr)) alist.ids[alist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); if (slist.nr == MPTCP_RM_IDS_MAX || diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info) lock_sock(sk); spin_lock_bh(&msk->pm.lock); - if (mptcp_pm_alloc_anno_list(msk, &addr_val.addr)) { + if (mptcp_pm_announced_alloc(msk, &addr_val.addr)) { msk->pm.add_addr_signaled++; mptcp_pm_announce_addr(msk, &addr_val.addr, false); mptcp_pm_addr_send_ack(msk); @@ -XXX,XX +XXX,XX @@ void mptcp_pm_remove_addr_entry(struct mptcp_sock *msk, int anno_nr = 0; /* only delete if either announced or matching a subflow */ - if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) + if (mptcp_pm_announced_remove(msk, &entry->addr)) anno_nr++; else if (!mptcp_pm_has_subflow_saddr(msk, &entry->addr)) return; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk, struct mptcp_addr_info *addr, struct mptcp_addr_info *rem, u8 bkup); -bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, +bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); -bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk); struct mptcp_pm_add_addr * -mptcp_pm_del_add_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id); +mptcp_pm_announced_del_timer(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr, bool check_id); +bool mptcp_pm_announced_remove(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr); +bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *ssk); bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, const struct mptcp_addr_info *saddr); -bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr); int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local, struct genl_info *info); int mptcp_userspace_pm_set_flags(struct mptcp_pm_addr_entry *local, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -XXX,XX +XXX,XX @@ static int subflow_check_req(struct request_sock *req, pr_debug("syn inet_sport=%d %d\n", ntohs(inet_sk(sk_listener)->inet_sport), ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport)); - if (!mptcp_pm_sport_in_anno_list(subflow_req->msk, sk_listener)) { + if (!mptcp_pm_announced_has_ssk(subflow_req->msk, sk_listener)) { SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX); subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT); return -EPERM; @@ -XXX,XX +XXX,XX @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, pr_debug("ack inet_sport=%d %d\n", ntohs(inet_sk(sk)->inet_sport), ntohs(inet_sk((struct sock *)owner)->inet_sport)); - if (!mptcp_pm_sport_in_anno_list(owner, sk)) { + if (!mptcp_pm_announced_has_ssk(owner, sk)) { SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTACKRX); subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT); goto dispose_child; -- 2.53.0
Similar to the two previous commits, using the 'add' prefix is confusing, also confirmed by [1]. Now that the structure has been renamed to include 'add_addr' in its name, easier to know the timer is linked to the ADD_ADDR, no need to add the confusing prefix, or an unneeded longer one. While at it, also update the ADD_ADDR timer helper to clearly specify it is linked to ADD_ADDR, and it is not there to add a new timer. Link: https://lore.kernel.org/20251117100745.1913963-1-edumazet@google.com [1] Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ struct mptcp_pm_add_addr { struct mptcp_addr_info addr; u8 retrans_times; bool timer_done; - struct timer_list add_timer; + struct timer_list timer; struct mptcp_sock *sock; struct rcu_head rcu; }; @@ -XXX,XX +XXX,XX @@ static unsigned int mptcp_adjust_add_addr_timeout(struct mptcp_sock *msk) return rto; } -static void mptcp_pm_add_timer(struct timer_list *timer) +static void mptcp_pm_add_addr_timer(struct timer_list *timer) { struct mptcp_pm_add_addr *entry = timer_container_of(entry, timer, - add_timer); + timer); struct mptcp_sock *msk = entry->sock; struct sock *sk = (struct sock *)msk; unsigned int timeout = 0; @@ -XXX,XX +XXX,XX @@ mptcp_pm_announced_del_timer(struct mptcp_sock *msk, */ if (stop_timer) { if (check_id) - sk_stop_timer(sk, &entry->add_timer); + sk_stop_timer(sk, &entry->timer); else - sk_stop_timer_sync(sk, &entry->add_timer); + sk_stop_timer_sync(sk, &entry->timer); } rcu_read_unlock(); @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, add_entry->sock = msk; add_entry->retrans_times = 0; - timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0); + timer_setup(&add_entry->timer, mptcp_pm_add_addr_timer, 0); reset_timer: add_entry->timer_done = false; timeout = mptcp_adjust_add_addr_timeout(msk); if (timeout) - sk_reset_timer(sk, &add_entry->add_timer, jiffies + timeout); + sk_reset_timer(sk, &add_entry->timer, jiffies + timeout); return true; } @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_free_announced_list(struct mptcp_sock *msk) list_for_each_entry_safe(entry, tmp, &free_list, list) { if (!entry->timer_done) - sk_stop_timer_sync(sk, &entry->add_timer); + sk_stop_timer_sync(sk, &entry->timer); kfree_rcu(entry, rcu); } } -- 2.53.0
Only used in pm.c. Note that the signature is added above: it is easier than moving the code around, because this helper depends on mptcp_pm_schedule_work which is declared below. While at it, explicitly mark it as to be called while pm->lock is held. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 4 +++- net/mptcp/protocol.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ static bool subflow_in_rm_list(const struct mptcp_subflow_context *subflow, return false; } +static void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk); static void mptcp_pm_addr_send_ack_avoid_list(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list) @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, spin_unlock_bh(&pm->lock); } -void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk) +/* To be called while pm->lock is held */ +static void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk) { if (!mptcp_pm_should_add_signal(msk)) return; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_received(const struct sock *ssk, const struct mptcp_addr_info *addr); void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); -void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk); void mptcp_pm_send_ack(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, bool prio, bool backup); -- 2.53.0
mptcp_pm_announced_del_timer() removes the matched ADD_ADDR entry (if found) from the ADD_ADDR list only if check_id is false. That's dangerous, and not clear, because it means the caller should be free the entry only in some cases, and it easy to miss that. Instead, make it static, and call it from mptcp_pm_add_addr_echoed, which is the only other case where mptcp_pm_add_addr_del_timer should be called with check_id set to true. Bonus with that: a second call to mptcp_pm_add_addr_lookup_by_addr() can be avoided. Note that instead of adding the signature above to avoid a compilation issue because this helper is called before the definition of the function, the whole helper is moved above where it is first called. Its content is untouched, except the addition of the 'static' keyboard. Reviewed-by: Mat Martineau <martineau@kernel.org> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 1 - net/mptcp/pm.c | 75 +++++++++++++++++++++++++++------------------------- net/mptcp/protocol.h | 3 --- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR); } else { mptcp_pm_add_addr_echoed(msk, &mp_opt.addr); - mptcp_pm_announced_del_timer(msk, &mp_opt.addr, true); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD); } diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ mptcp_pm_announced_lookup(const struct mptcp_sock *msk, return NULL; } +static struct mptcp_pm_add_addr * +mptcp_pm_announced_del_timer(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr, bool check_id) +{ + struct sock *sk = (struct sock *)msk; + struct mptcp_pm_add_addr *entry; + bool stop_timer = false; + + rcu_read_lock(); + + spin_lock_bh(&msk->pm.lock); + entry = mptcp_pm_announced_lookup(msk, addr); + if (entry && (!check_id || entry->addr.id == addr->id)) { + entry->retrans_times = ADD_ADDR_RETRANS_MAX; + stop_timer = true; + } + if (!check_id && entry) + list_del(&entry->list); + spin_unlock_bh(&msk->pm.lock); + + /* 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) { + if (check_id) + sk_stop_timer(sk, &entry->timer); + else + sk_stop_timer_sync(sk, &entry->timer); + } + + rcu_read_unlock(); + return entry; +} + bool mptcp_pm_announced_remove(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_addr_timer(struct timer_list *timer) sock_put(sk); } -struct mptcp_pm_add_addr * -mptcp_pm_announced_del_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id) -{ - struct sock *sk = (struct sock *)msk; - struct mptcp_pm_add_addr *entry; - bool stop_timer = false; - - rcu_read_lock(); - - spin_lock_bh(&msk->pm.lock); - entry = mptcp_pm_announced_lookup(msk, addr); - if (entry && (!check_id || entry->addr.id == addr->id)) { - entry->retrans_times = ADD_ADDR_RETRANS_MAX; - stop_timer = true; - } - if (!check_id && entry) - list_del(&entry->list); - spin_unlock_bh(&msk->pm.lock); - - /* 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) { - if (check_id) - sk_stop_timer(sk, &entry->timer); - else - sk_stop_timer_sync(sk, &entry->timer); - } - - rcu_read_unlock(); - return entry; -} - bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { struct mptcp_pm_data *pm = &msk->pm; + struct mptcp_pm_add_addr *entry; pr_debug("msk=%p\n", msk); - if (!READ_ONCE(pm->work_pending)) + entry = mptcp_pm_announced_del_timer(msk, addr, true); + + if (!entry || !READ_ONCE(pm->work_pending)) return; spin_lock_bh(&pm->lock); - if (mptcp_pm_announced_lookup(msk, addr) && READ_ONCE(pm->work_pending)) + if (READ_ONCE(pm->work_pending)) mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED); spin_unlock_bh(&pm->lock); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk, u8 bkup); bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); -struct mptcp_pm_add_addr * -mptcp_pm_announced_del_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id); bool mptcp_pm_announced_remove(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *ssk); -- 2.53.0
It was passed since its introduction in commit dc87efdb1a5c ("mptcp: add mptcp reset option support"), but never used. Simply removes it. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_mp_prio(struct sock *sk, int *size, return true; } -static noinline bool mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb, +static noinline bool mptcp_established_options_rst(struct sock *sk, int *size, unsigned int remaining, struct mptcp_out_options *opts) @@ -XXX,XX +XXX,XX @@ int mptcp_established_options(struct sock *sk, struct sk_buff *skb, remaining -= opt_size; } /* MP_RST can be used with MP_FASTCLOSE and MP_FAIL if there is room */ - if (mptcp_established_options_rst(sk, skb, &opt_size, remaining, opts)) { + if (mptcp_established_options_rst(sk, &opt_size, remaining, opts)) { total_size += opt_size; remaining -= opt_size; } -- 2.53.0
Currently, it is possible to add a "signal" MPTCP endpoint with a v6 address and a port, or to directly request to send an ADD_ADDR with a v6 address and a port, but such signalling option cannot be sent when TCP timestamps is used due to a lack of option space. Instead of simply dropping such ADD_ADDR, the TCP timestamps can be dropped only for this packet. - Patch 1: fix for PREEMPT_RT kernels, for -net. - Patches 2-4: small cleanups to avoid computing ADD/RM_ADDR twice. - Patches 5-8: the new feature, controlled by a new sysctl knob. - Patch 9: extra checks in the selftests. - Patches 10-16: refactoring/cleanups: some of them were part of a previous patch: "mptcp: pm: clearer ADD_ADDR related helpers names" [1]. Note that the mptcp/add_addr/add_addr6_port_ts_server.pkt packetdrill test is supposed to fail with this series, until this PR is applied: https://github.com/multipath-tcp/packetdrill/pull/198 Link: https://lore.kernel.org/20260415-mptcp-inc-limits-v5-20-e54c3bf80e4e@kernel.org [1] Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- Changes in v3: - Patch 1: sk_stop_timer() should still be called under rcu. - Patches 6-7: split + s/has_ts/add_addr_drop_ts/. - Link to v2: https://patch.msgid.link/20260519-mptcp-add-addr6-port-ts-v2-0-3b36a51e6a86@kernel.org Changes in v2: - Patch 1: new. - Patch 3: reset size in mptcp_pm_add_addr_signal for dropped options. - Patches 4-5: split from previous patch 3. (Paolo) - Patch 4: fix typo. - Patch 5: fix reverse Xmas tree order + change label. (Paolo) - Patch 6: back to v6 connection. - Patch 10: fix comment. - Patch 14: fix typo. - Link to v1: https://patch.msgid.link/20260518-mptcp-add-addr6-port-ts-v1-0-f1ca26977fcd@kernel.org --- Matthieu Baerts (NGI0) (16): [mptcp-net] mptcp: pm: avoid sleeping while holding rcu_read_lock mptcp: options: ADD_ADDR size can be negative mptcp: pm: avoid computing rm_addr size twice mptcp: pm: avoid computing add_addr size twice mptcp: introduce add_addr_v6_port_drop_ts sysctl knob tcp: allow mptcp to drop TS for some packets mptcp: pm: drop TCP TS with ADD_ADDRv6 + port selftests: mptcp: validate ADD_ADDRv6 + TS + port selftests: mptcp: always check sent/dropped ADD_ADDRs mptcp: pm: use for_each_subflow helper mptcp: pm: rename add_entry structure to add_addr mptcp: pm: uniform announced addresses helpers mptcp: pm: remove add_ prefix from timer mptcp: pm: make mptcp_pm_add_addr_send_ack static mptcp: pm: avoid using del_timer directly mptcp: pm: avoid confusing check_id in del_timer Documentation/networking/mptcp-sysctl.rst | 13 ++ include/net/mptcp.h | 3 +- net/ipv4/tcp_output.c | 6 +- net/mptcp/ctrl.c | 18 ++- net/mptcp/options.c | 43 ++---- net/mptcp/pm.c | 189 ++++++++++++++---------- net/mptcp/pm_kernel.c | 22 +-- net/mptcp/pm_userspace.c | 6 +- net/mptcp/protocol.h | 46 ++---- net/mptcp/subflow.c | 4 +- tools/testing/selftests/net/mptcp/mptcp_join.sh | 83 +++++------ 11 files changed, 232 insertions(+), 201 deletions(-) --- base-commit: 08d7466136ffa606d823f1fc4879f97d366d9e92 change-id: 20260508-mptcp-add-addr6-port-ts-371653e0f843 Best regards, -- Matthieu Baerts (NGI0) <matttbe@kernel.org>
sk_stop_timer_sync() calls del_timer_sync(), which spin-waits for the timer callback to complete on non-RT kernels. But on PREEMPT_RT, it can sleep. Sleeping inside an RCU read-side critical section might trigger a lockdep splat. Instead, keep a reference to the timer, under rcu_read_lock, and call sk_stop_timer*() without the RCU lock. While at it, apply the reversed Xmas order when declaring variables. Fixes: 426358d9be7c ("mptcp: fix a race in mptcp_pm_del_add_timer()") Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- For -net. v3: sk_stop_timer() should still be called under rcu. --- net/mptcp/pm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ struct mptcp_pm_add_entry * mptcp_pm_del_add_timer(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool check_id) { - struct mptcp_pm_add_entry *entry; struct sock *sk = (struct sock *)msk; - bool stop_timer = false; + struct mptcp_pm_add_entry *entry; + struct timer_list *timer = NULL; rcu_read_lock(); @@ -XXX,XX +XXX,XX @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, entry = mptcp_lookup_anno_list_by_saddr(msk, addr); if (entry && (!check_id || entry->addr.id == addr->id)) { entry->retrans_times = ADD_ADDR_RETRANS_MAX; - stop_timer = true; + timer = &entry->add_timer; } if (!check_id && entry) list_del(&entry->list); @@ -XXX,XX +XXX,XX @@ 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) { - if (check_id) - sk_stop_timer(sk, &entry->add_timer); - else - sk_stop_timer_sync(sk, &entry->add_timer); - } + if (timer && check_id) + sk_stop_timer(sk, timer); rcu_read_unlock(); + + if (timer && !check_id) + sk_stop_timer_sync(sk, timer); + return entry; } -- 2.53.0
Use a signed int for the returned size, because if other options are dropped, the size can be negative, e.g. to send an echo ADD_ADDR with a v4 address, and no port. The behaviour is not changed, because it was working as expected with an overflow. But it is clearer like this, and it will help later on. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static u64 add_addr_generate_hmac(u64 key1, u64 key2, return get_unaligned_be64(&hmac[SHA256_DIGEST_SIZE - sizeof(u64)]); } -static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *skb, - unsigned int *size, +static bool mptcp_established_options_add_addr(struct sock *sk, + struct sk_buff *skb, int *size, unsigned int remaining, struct mptcp_out_options *opts) { @@ -XXX,XX +XXX,XX @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); - unsigned int opt_size = 0; bool snd_data_fin; bool ret = false; + int opt_size = 0; opts->suboptions = 0; -- 2.53.0
mptcp_rm_addr_len helper was called twice: in mptcp_pm_rm_addr_signal, then just after in mptcp_established_options_rm_addr. Both to check the remaining space. The second call is not needed: if there is not enough space, mptcp_pm_rm_addr_signal will return false, and the caller, mptcp_established_options_rm_addr, will do the same without re-checking the size again. Instead, mptcp_pm_rm_addr_signal can directly set the size. While at it, move mptcp_rm_addr_len to pm.c, as it is now only used there, once. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 11 ++--------- net/mptcp/pm.c | 11 ++++++++++- net/mptcp/protocol.h | 10 +--------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_rm_addr(struct sock *sk, struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); struct mptcp_rm_list rm_list; - int i, len; + int i; if (!mptcp_pm_should_rm_signal(msk) || - !(mptcp_pm_rm_addr_signal(msk, remaining, &rm_list))) + !(mptcp_pm_rm_addr_signal(msk, remaining, &rm_list, size))) return false; - len = mptcp_rm_addr_len(&rm_list); - if (len < 0) - return false; - if (remaining < len) - return false; - - *size = len; opts->suboptions |= OPTION_MPTCP_RM_ADDR; opts->rm_list = rm_list; diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, return ret; } +static int mptcp_rm_addr_len(const struct mptcp_rm_list *rm_list) +{ + if (rm_list->nr == 0 || rm_list->nr > MPTCP_RM_IDS_MAX) + return -EINVAL; + + return TCPOLEN_MPTCP_RM_ADDR_BASE + roundup(rm_list->nr - 1, 4) + 1; +} + bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, - struct mptcp_rm_list *rm_list) + struct mptcp_rm_list *rm_list, unsigned int *size) { int ret = false, len; u8 rm_addr; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, if (remaining < len) goto out_unlock; + *size = len; *rm_list = msk->pm.rm_list_tx; WRITE_ONCE(msk->pm.addr_signal, rm_addr); ret = true; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ static inline unsigned int mptcp_add_addr_len(int family, bool echo, bool port) return len; } -static inline int mptcp_rm_addr_len(const struct mptcp_rm_list *rm_list) -{ - if (rm_list->nr == 0 || rm_list->nr > MPTCP_RM_IDS_MAX) - return -EINVAL; - - return TCPOLEN_MPTCP_RM_ADDR_BASE + roundup(rm_list->nr - 1, 4) + 1; -} - bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, unsigned int opt_size, unsigned int remaining, struct mptcp_addr_info *addr, bool *echo, bool *drop_other_suboptions); bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, - struct mptcp_rm_list *rm_list); + struct mptcp_rm_list *rm_list, unsigned int *len); int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); bool mptcp_pm_is_backup(struct mptcp_sock *msk, struct sock_common *skc); int mptcp_pm_nl_dump_addr(struct sk_buff *msg, -- 2.53.0
mptcp_add_addr_len helper was called twice: in mptcp_pm_add_addr_signal, then just after in mptcp_established_options_add_addr. Both to check the remaining space. The second call is not needed: if there is not enough space, mptcp_pm_add_addr_signal will return false, and the caller, mptcp_established_options_add_addr, will do the same without re-checking the size again. Instead, mptcp_pm_add_addr_signal can directly set the size. Note that the returned size can be negative when other suboptions are dropped, e.g. to send an echo ADD_ADDR with a v4 address, and no port. While at it, move mptcp_add_addr_len to pm.c, as it is now only used from there, once, and use a bool for 'ret' in mptcp_pm_add_addr_signal. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: reset size in mptcp_pm_add_addr_signal if other options are dropped. --- net/mptcp/options.c | 16 +++------------- net/mptcp/pm.c | 26 ++++++++++++++++++++++---- net/mptcp/protocol.h | 17 +---------------- 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); bool drop_other_suboptions = false; - unsigned int opt_size = *size; struct mptcp_addr_info addr; bool echo; - int len; /* add addr will strip the existing options, be sure to avoid breaking * MPC/MPJ handshakes */ if (!mptcp_pm_should_add_signal(msk) || (opts->suboptions & (OPTION_MPTCP_MPJ_ACK | OPTION_MPTCP_MPC_ACK)) || - !mptcp_pm_add_addr_signal(msk, skb, opt_size, remaining, &addr, - &echo, &drop_other_suboptions)) + !mptcp_pm_add_addr_signal(msk, skb, size, remaining, &addr, &echo, + &drop_other_suboptions)) return false; /* * Later on, mptcp_write_options() will enforce mutually exclusion with * DSS, bail out if such option is set and we can't drop it. */ - if (drop_other_suboptions) - remaining += opt_size; - else if (opts->suboptions & OPTION_MPTCP_DSS) + if (!drop_other_suboptions && opts->suboptions & OPTION_MPTCP_DSS) return false; - len = mptcp_add_addr_len(addr.family, echo, !!addr.port); - if (remaining < len) - return false; - - *size = len; if (drop_other_suboptions) { pr_debug("drop other suboptions\n"); opts->suboptions = 0; @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_add_addr(struct sock *sk, * options */ opts->ahmac = 0; - *size -= opt_size; } opts->addr = addr; opts->suboptions |= OPTION_MPTCP_ADD_ADDR; diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq) } } +static unsigned int mptcp_add_addr_len(int family, bool echo, bool port) +{ + u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE; + + if (family == AF_INET6) + len = TCPOLEN_MPTCP_ADD_ADDR6_BASE; + if (!echo) + len += MPTCPOPT_THMAC_LEN; + /* account for 2 trailing 'nop' options */ + if (port) + len += TCPOLEN_MPTCP_PORT_LEN + TCPOLEN_MPTCP_PORT_ALIGN; + + return len; +} + bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, - unsigned int opt_size, unsigned int remaining, + int *size, int remaining, struct mptcp_addr_info *addr, bool *echo, bool *drop_other_suboptions) { bool skip_add_addr = false; - int ret = false; + bool ret = false; u8 add_addr; + int len = 0; u8 family; bool port; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, * if any, will be carried by the 'original' TCP ack */ if (skb && skb_is_tcp_pure_ack(skb)) { - remaining += opt_size; + len -= *size; *drop_other_suboptions = true; } @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, family = msk->pm.local.family; } - if (remaining < mptcp_add_addr_len(family, *echo, port)) { + len += mptcp_add_addr_len(family, *echo, port); + if (len > remaining) { struct net *net = sock_net((struct sock *)msk); if (!*drop_other_suboptions) @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, } ret = true; + *size = len; drop_signal_mark: WRITE_ONCE(msk->pm.addr_signal, add_addr); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ static inline bool mptcp_pm_is_kernel(const struct mptcp_sock *msk) return READ_ONCE(msk->pm.pm_type) == MPTCP_PM_TYPE_KERNEL; } -static inline unsigned int mptcp_add_addr_len(int family, bool echo, bool port) -{ - u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE; - - if (family == AF_INET6) - len = TCPOLEN_MPTCP_ADD_ADDR6_BASE; - if (!echo) - len += MPTCPOPT_THMAC_LEN; - /* account for 2 trailing 'nop' options */ - if (port) - len += TCPOLEN_MPTCP_PORT_LEN + TCPOLEN_MPTCP_PORT_ALIGN; - - return len; -} - bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, - unsigned int opt_size, unsigned int remaining, + int *size, int remaining, struct mptcp_addr_info *addr, bool *echo, bool *drop_other_suboptions); bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, -- 2.53.0
This sysctl is going to be used in the next commits to drop TCP timestamps option, to be able to send an ADD_ADDR with a v6 IP address and a port number. It is enabled by default. This knob is explicitly disabled in the MPTCP Join selftest, with the "signal addr list progresses after tx drop" subtest, to continue verifying the previous behaviour where the ADD_ADDR is not sent due to a lack of space. While at it, move syn_retrans_before_tcp_fallback down from struct mptcp_pernet, to avoid creating another 3 bytes hole. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: split (Paolo) + fix new sysctl name in selftests. --- Documentation/networking/mptcp-sysctl.rst | 13 +++++++++++++ net/mptcp/ctrl.c | 18 +++++++++++++++++- net/mptcp/protocol.h | 1 + tools/testing/selftests/net/mptcp/mptcp_join.sh | 1 + 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/mptcp-sysctl.rst b/Documentation/networking/mptcp-sysctl.rst index XXXXXXX..XXXXXXX 100644 --- a/Documentation/networking/mptcp-sysctl.rst +++ b/Documentation/networking/mptcp-sysctl.rst @@ -XXX,XX +XXX,XX @@ add_addr_timeout - INTEGER (seconds) Default: 120 +add_addr_v6_port_drop_ts - BOOLEAN + Control whether preparing an ADD_ADDR with an IPv6 address and a port + should drop the TCP timestamps option to have enough option space to + send the signal. + + If there is not enough option space, and the TCP timestamps option + cannot be dropped, the signal cannot be sent. Note that dropping the TCP + timestamps option for one packet of the connection could disrupt some + middleboxes: even if it should be unlikely, they could drop the packet + or block the connection. This is a per-namespace sysctl. + + Default: 1 (enabled) + allow_join_initial_addr_port - BOOLEAN Allow peers to send join requests to the IP address and port number used by the initial subflow if the value is 1. This controls a flag that is diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -XXX,XX +XXX,XX @@ struct mptcp_pernet { unsigned int close_timeout; unsigned int stale_loss_cnt; atomic_t active_disable_times; - u8 syn_retrans_before_tcp_fallback; unsigned long active_disable_stamp; + u8 syn_retrans_before_tcp_fallback; u8 mptcp_enabled; u8 checksum_enabled; u8 allow_join_initial_addr_port; u8 pm_type; + u8 add_addr_v6_port_drop_ts; char scheduler[MPTCP_SCHED_NAME_MAX]; char path_manager[MPTCP_PM_NAME_MAX]; }; @@ -XXX,XX +XXX,XX @@ const char *mptcp_get_scheduler(const struct net *net) return mptcp_get_pernet(net)->scheduler; } +unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net) +{ + return mptcp_get_pernet(net)->add_addr_v6_port_drop_ts; +} + static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet) { pernet->mptcp_enabled = 1; @@ -XXX,XX +XXX,XX @@ static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet) pernet->pm_type = MPTCP_PM_TYPE_KERNEL; strscpy(pernet->scheduler, "default", sizeof(pernet->scheduler)); strscpy(pernet->path_manager, "kernel", sizeof(pernet->path_manager)); + pernet->add_addr_v6_port_drop_ts = 1; } #ifdef CONFIG_SYSCTL @@ -XXX,XX +XXX,XX @@ static struct ctl_table mptcp_sysctl_table[] = { .mode = 0444, .proc_handler = proc_available_path_managers, }, + { + .procname = "add_addr_v6_port_drop_ts", + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE + }, }; static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) @@ -XXX,XX +XXX,XX @@ static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) table[10].data = &pernet->syn_retrans_before_tcp_fallback; table[11].data = &pernet->path_manager; /* table[12] is for available_path_managers which is read-only info */ + table[13].data = &pernet->add_addr_v6_port_drop_ts; hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table, ARRAY_SIZE(mptcp_sysctl_table)); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ unsigned int mptcp_close_timeout(const struct sock *sk); int mptcp_get_pm_type(const struct net *net); const char *mptcp_get_path_manager(const struct net *net); const char *mptcp_get_scheduler(const struct net *net); +unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net); void mptcp_active_disable(struct sock *sk); bool mptcp_active_should_disable(struct sock *ssk); diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index XXXXXXX..XXXXXXX 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -XXX,XX +XXX,XX @@ add_addr_ports_tests() 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.mptcp.add_addr_v6_port_drop_ts=0 2>/dev/null || true ip netns exec $ns1 sysctl -q net.ipv4.tcp_timestamps=1 ip netns exec $ns2 sysctl -q net.ipv4.tcp_timestamps=1 -- 2.53.0
With TCP-timestamps (padded) taking 12 bytes and ADD_ADDR IPv6 + port taking 30 bytes, the 40-byte limit for the TCP options is reached. In this case, it is then not possible to send the address signal. The idea is to let MPTCP dropping the TCP-timestamps option for some specific packets, to be able to send some specific pure ACK carrying >28 bytes of MPTCP options, like with this specific ADD_ADDR. A new parameter is passed from tcp_established_options to the MPTCP side to indicate if the TCP TS option is used, and if it should be dropped. The next commit implements the part on MPTCP side, but split into two patches to help TCP maintainers to identify the modifications on TCP side. This feature will be controlled by a new add_addr_v6_port_drop_ts MPTCP sysctl knob. It is important to keep in mind that dropping the TCP timestamps option for one packet of the connection could eventually disrupt some middleboxes: even if it should be unlikely, they could drop the packet or even block the connection. That's why this new feature will be controlled by a sysctl knob. Note that it would be technically possible to squeeze both options into the header if the ADD_ADDR is first written, and then the TCP timestamps without the NOPs preceding it. But this means more modifications on TCP side, plus some middleboxes could still be disrupted by that. About the implementation, instead of passing a new boolean (drop_ts), another option would be to pass the whole option structure (opts), but 'struct tcp_out_options' is currently defined in tcp_output.c, and would need to be exported. Plus that means the removal of the TCP TS option would be done on the MPTCP side, and not here on the TCP side. It feels clearer to remove other TCP options from the TCP side, than hiding that from the MPTCP side. Yet an other alternative would be to pass the size already taken by the other TCP options, and have a way to drop them all when needed. But this feels better to target only the timestamps option where dropping it should be safe, even if it is currently the only option that would be set before MPTCP, when MPTCP is used. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v3: split from the next commit --- include/net/mptcp.h | 3 ++- net/ipv4/tcp_output.c | 6 +++++- net/mptcp/options.c | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index XXXXXXX..XXXXXXX 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -XXX,XX +XXX,XX @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size, struct mptcp_out_options *opts); bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, unsigned int *size, unsigned int remaining, - struct mptcp_out_options *opts); + bool *drop_ts, struct mptcp_out_options *opts); bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb); void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp, @@ -XXX,XX +XXX,XX @@ static inline bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, unsigned int *size, unsigned int remaining, + bool *drop_ts, struct mptcp_out_options *opts) { return false; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index XXXXXXX..XXXXXXX 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -XXX,XX +XXX,XX @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb */ if (sk_is_mptcp(sk)) { unsigned int remaining = MAX_TCP_OPTION_SPACE - size; + bool drop_ts = opts->options & OPTION_TS; unsigned int opt_size = 0; if (mptcp_established_options(sk, skb, &opt_size, remaining, - &opts->mptcp)) { + &drop_ts, &opts->mptcp)) { opts->options |= OPTION_MPTCP; size += opt_size; + + if (drop_ts) + opts->options &= ~OPTION_TS; } } diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_mp_fail(struct sock *sk, bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, unsigned int *size, unsigned int remaining, - struct mptcp_out_options *opts) + bool *drop_ts, struct mptcp_out_options *opts) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); @@ -XXX,XX +XXX,XX @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, int opt_size = 0; opts->suboptions = 0; + *drop_ts = false; /* Force later mptcp_write_options(), but do not use any actual * option space. -- 2.53.0
With TCP-timestamps (padded) taking 12 bytes and ADD_ADDR IPv6 + port taking 30 bytes, the 40-byte limit for the TCP options is reached. In this case, it is then not possible to send the signal. To be able to send this ADD_ADDR, the TCP timestamps option can now be dropped. This is done, when needed by setting the *drop_ts parameter from mptcp_established_options. This feature is controlled by a new net.mptcp.add_addr_v6_port_drop_ts sysctl knob, enabled by default. It is important to keep in mind that dropping the TCP timestamps option for one packet of the connection could eventually disrupt some middleboxes: even if it should be unlikely, they could drop the packet or even block the connection. That's why this new feature can be controlled by a sysctl knob. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/448 Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: split + fix reverse Xmas tree order + change label (Paolo) v3: split the TCP part in the previous patch + s/has_ts/add_addr_drop_ts --- net/mptcp/options.c | 8 ++++++-- net/mptcp/pm.c | 12 +++++++++++- net/mptcp/protocol.h | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ static u64 add_addr_generate_hmac(u64 key1, u64 key2, static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *skb, int *size, unsigned int remaining, + bool *drop_ts, struct mptcp_out_options *opts) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); @@ -XXX,XX +XXX,XX @@ static bool mptcp_established_options_add_addr(struct sock *sk, if (!mptcp_pm_should_add_signal(msk) || (opts->suboptions & (OPTION_MPTCP_MPJ_ACK | OPTION_MPTCP_MPC_ACK)) || !mptcp_pm_add_addr_signal(msk, skb, size, remaining, &addr, &echo, - &drop_other_suboptions)) + &drop_other_suboptions, drop_ts)) return false; /* @@ -XXX,XX +XXX,XX @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); + bool add_addr_drop_ts = *drop_ts; bool snd_data_fin; bool ret = false; int opt_size = 0; @@ -XXX,XX +XXX,XX @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, *size += opt_size; remaining -= opt_size; - if (mptcp_established_options_add_addr(sk, skb, &opt_size, remaining, opts)) { + if (mptcp_established_options_add_addr(sk, skb, &opt_size, remaining, + &add_addr_drop_ts, opts)) { *size += opt_size; remaining -= opt_size; ret = true; + *drop_ts = add_addr_drop_ts; } else if (mptcp_established_options_rm_addr(sk, &opt_size, remaining, opts)) { *size += opt_size; remaining -= opt_size; diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ static unsigned int mptcp_add_addr_len(int family, bool echo, bool port) bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, int *size, int remaining, struct mptcp_addr_info *addr, bool *echo, - bool *drop_other_suboptions) + bool *drop_other_suboptions, bool *drop_ts) { bool skip_add_addr = false; bool ret = false; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, if (!*drop_other_suboptions) goto out_unlock; + if (*drop_ts && mptcp_add_addr_v6_port_drop_ts(net)) { + /* OK without TCP Timestamps? */ + len -= TCPOLEN_TSTAMP_ALIGNED; + if (len <= remaining) + goto enough_space; + } + if (*echo) { MPTCP_INC_STATS(net, MPTCP_MIB_ECHOADDTXDROP); } else { @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, goto drop_signal_mark; } + *drop_ts = false; + +enough_space: ret = true; *size = len; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ static inline bool mptcp_pm_is_kernel(const struct mptcp_sock *msk) bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, int *size, int remaining, struct mptcp_addr_info *addr, bool *echo, - bool *drop_other_suboptions); + bool *drop_other_suboptions, bool *drop_ts); bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, struct mptcp_rm_list *rm_list, unsigned int *len); int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); -- 2.53.0
This validates the feature added by parent commit, where it is now possible to send an ADD_ADDR with a v6 IP address and a port number, while the connection is using TCP Timestamps. This test is simply a copy of the previous one: "signal address with port", but using IPv6 addresses. This test is only executed if the add_addr_v6_port_drop_ts sysctl knob is available. If not, it means the kernel doesn't support this feature. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: switch back to IPv6 for the main connection to use a v6 socket. --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index XXXXXXX..XXXXXXX 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -XXX,XX +XXX,XX @@ add_addr_ports_tests() chk_add_nr 1 1 1 fi + # signal address v6 with port + if reset "signal address v6 with port" && + continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/add_addr_v6_port_drop_ts'; then + pm_nl_set_limits $ns1 0 1 + pm_nl_set_limits $ns2 1 1 + pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal port 10100 + run_tests $ns1 $ns2 dead:beef:1::1 + chk_join_nr 1 1 1 + chk_add_nr 1 1 1 + fi + # subflow and signal with port if reset "subflow and signal with port"; then pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 -- 2.53.0
Before, they were only checked on demand, but it seems better to check them each time received ADD_ADDRs are checked. Errors are only reported when the counter exists, and the value is not the expected one. This is similar to what is done in chk_join_nr: it reduces the output, and avoids a lot of 'skip' when validating older kernels. Also here, some tests need to adapt the default expected counters, e.g. when ADD_ADDR echo are dropped on the reception side, or it is not possible to send an ADD_ADDR due to the limited option space. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 71 ++++++++++--------------- 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index XXXXXXX..XXXXXXX 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -XXX,XX +XXX,XX @@ unset fb_mpc_data unset fb_md5_sig unset fb_dss +unset add_addr_tx_nr +unset add_addr_echo_tx_nr +unset add_addr_drop_tx_nr + # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" CBPF_MPTCP_SUBOPTION_ADD_ADDR="14, @@ -XXX,XX +XXX,XX @@ chk_add_nr() local ack_nr=$port_nr local mis_syn_nr=0 local mis_ack_nr=0 + local add_tx_nr=${add_addr_tx_nr:-${add_nr}} + local echo_tx_nr=${add_addr_echo_tx_nr:-${echo_nr}} + local drop_tx_nr=${add_addr_drop_tx_nr:-0} local ns_tx=$ns1 local ns_rx=$ns2 local tx="" @@ -XXX,XX +XXX,XX @@ chk_add_nr() print_ok fi fi -} -chk_add_tx_nr() -{ - local add_tx_nr=$1 - local echo_tx_nr=$2 - local count - - print_check "add addr tx" - count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtAddAddrTx") - if [ -z "$count" ]; then - print_skip + count=$(mptcp_lib_get_counter ${ns_tx} "MPTcpExtAddAddrTx") # Tolerate more ADD_ADDR then expected (if any), due to retransmissions - elif [ "$count" != "$add_tx_nr" ] && - { [ "$add_tx_nr" -eq 0 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + if [ -n "$count" ] && [ "$count" != "$add_tx_nr" ] && + { [ "$add_tx_nr" -eq 0 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + print_check "add addr tx" fail_test "got $count ADD_ADDR[s] TX, expected $add_tx_nr" - else - print_ok fi - print_check "add addr echo tx" - count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtEchoAddTx") - if [ -z "$count" ]; then - print_skip - elif [ "$count" != "$echo_tx_nr" ]; then + count=$(mptcp_lib_get_counter ${ns_rx} "MPTcpExtEchoAddTx") + if [ -n "$count" ] && [ "$count" != "$echo_tx_nr" ]; then + print_check "add addr echo tx" fail_test "got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" - else - print_ok 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 + count=$(mptcp_lib_get_counter ${ns_tx} "MPTcpExtAddAddrTxDrop") + if [ -n "$count" ] && [ "$count" != "$drop_tx_nr" ]; then + print_check "add addr tx drop" fail_test "got $count ADD_ADDR drop[s] TX, expected $drop_tx_nr" - else - print_ok fi } @@ -XXX,XX +XXX,XX @@ signal_address_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 - chk_add_tx_nr 1 1 chk_add_nr 1 1 fi @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() speed=slow \ run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 1 1 1 - chk_add_tx_nr 4 4 - chk_add_nr 4 0 + add_addr_echo_tx_nr=4 \ + chk_add_nr 4 0 fi # add_addr timeout IPv6 @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() speed=slow \ run_tests $ns1 $ns2 dead:beef:1::1 chk_join_nr 1 1 1 - chk_add_nr 4 0 + add_addr_echo_tx_nr=4 \ + chk_add_nr 4 0 fi # signal addresses timeout @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() speed=10 \ run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 - chk_add_nr 8 0 + add_addr_echo_tx_nr=8 \ + chk_add_nr 8 0 fi # signal invalid addresses timeout @@ -XXX,XX +XXX,XX @@ add_addr_timeout_tests() run_tests $ns1 $ns2 10.0.1.1 join_syn_tx=2 \ chk_join_nr 1 1 1 - chk_add_nr 8 0 + add_addr_echo_tx_nr=7 \ + chk_add_nr 8 0 fi } @@ -XXX,XX +XXX,XX @@ add_addr_ports_tests() 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 + add_addr_drop_tx_nr=1 \ + chk_add_nr 1 1 0 fi } -- 2.53.0
Similar to most places in the MPTCP code. So instead of passing the subflow list and use list_for_each_entry(subflow, list, node), pass the msk and use mptcp_for_each_subflow(msk, subflow). That's clearer and more uniform with the rest. While at it, add 'pm_' prefix for the exported one to easily identify the origin. Plus replace 'lookup' by 'has', because a bool is returned. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 6 +++--- net/mptcp/pm_kernel.c | 12 ++++++------ net/mptcp/pm_userspace.c | 2 +- net/mptcp/protocol.h | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ static bool mptcp_pm_is_init_remote_addr(struct mptcp_sock *msk, return mptcp_addresses_equal(&mpc_remote, remote, remote->port); } -bool mptcp_lookup_subflow_by_saddr(const struct list_head *list, - const struct mptcp_addr_info *saddr) +bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, + const struct mptcp_addr_info *saddr) { struct mptcp_subflow_context *subflow; struct mptcp_addr_info cur; struct sock_common *skc; - list_for_each_entry(subflow, list, node) { + mptcp_for_each_subflow(msk, subflow) { skc = (struct sock_common *)mptcp_subflow_tcp_sock(subflow); mptcp_local_address(skc, &cur); diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -XXX,XX +XXX,XX @@ u8 mptcp_pm_get_limit_extra_subflows(const struct mptcp_sock *msk) } EXPORT_SYMBOL_GPL(mptcp_pm_get_limit_extra_subflows); -static bool lookup_subflow_by_daddr(const struct list_head *list, - const struct mptcp_addr_info *daddr) +static bool has_subflow_daddr(const struct mptcp_sock *msk, + const struct mptcp_addr_info *daddr) { struct mptcp_subflow_context *subflow; struct mptcp_addr_info cur; - list_for_each_entry(subflow, list, node) { + mptcp_for_each_subflow(msk, subflow) { struct sock *ssk = mptcp_subflow_tcp_sock(subflow); if (!((1 << inet_sk_state_load(ssk)) & @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk) mptcp_pm_addr_send_ack(msk); mptcp_mpc_endpoint_setup(msk); - if (lookup_subflow_by_daddr(&msk->conn_list, &remote)) + if (has_subflow_daddr(msk, &remote)) return; /* pick id 0 port, if none is provided the remote address */ @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, goto next; lock_sock(sk); - remove_subflow = mptcp_lookup_subflow_by_saddr(&msk->conn_list, addr); + remove_subflow = mptcp_pm_has_subflow_saddr(msk, addr); mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk, entry = list_prepare_entry(entry, rm_list, list); list_for_each_entry_continue(entry, rm_list, list) { - if (mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) + if (mptcp_pm_has_subflow_saddr(msk, &entry->addr)) slist.ids[slist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -XXX,XX +XXX,XX @@ void mptcp_pm_remove_addr_entry(struct mptcp_sock *msk, /* only delete if either announced or matching a subflow */ if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) anno_nr++; - else if (!mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) + else if (!mptcp_pm_has_subflow_saddr(msk, &entry->addr)) return; alist.ids[alist.nr++] = entry->addr.id; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk); struct mptcp_pm_add_entry * mptcp_pm_del_add_timer(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool check_id); -bool mptcp_lookup_subflow_by_saddr(const struct list_head *list, - const struct mptcp_addr_info *saddr); +bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, + const struct mptcp_addr_info *saddr); bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local, -- 2.53.0
Using only the 'add' prefix is confusing: does it refer to a generic added entry or address, or specifically to ADD_ADDRs. Using add_addr removes this confusion. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 22 +++++++++++----------- net/mptcp/protocol.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ #define ADD_ADDR_RETRANS_MAX 3 -struct mptcp_pm_add_entry { +struct mptcp_pm_add_addr { struct list_head list; struct mptcp_addr_info addr; u8 retrans_times; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, return false; } -static struct mptcp_pm_add_entry * +static struct mptcp_pm_add_addr * mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { - struct mptcp_pm_add_entry *entry; + struct mptcp_pm_add_addr *entry; lockdep_assert_held(&msk->pm.lock); @@ -XXX,XX +XXX,XX @@ mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { - struct mptcp_pm_add_entry *entry; + struct mptcp_pm_add_addr *entry; bool ret; entry = mptcp_pm_del_add_timer(msk, addr, false); @@ -XXX,XX +XXX,XX @@ bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk) { - struct mptcp_pm_add_entry *entry; + struct mptcp_pm_add_addr *entry; struct mptcp_addr_info saddr; bool ret = false; @@ -XXX,XX +XXX,XX @@ static unsigned int mptcp_adjust_add_addr_timeout(struct mptcp_sock *msk) static void mptcp_pm_add_timer(struct timer_list *timer) { - struct mptcp_pm_add_entry *entry = timer_container_of(entry, timer, - add_timer); + struct mptcp_pm_add_addr *entry = timer_container_of(entry, timer, + add_timer); struct mptcp_sock *msk = entry->sock; struct sock *sk = (struct sock *)msk; unsigned int timeout = 0; @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_timer(struct timer_list *timer) sock_put(sk); } -struct mptcp_pm_add_entry * +struct mptcp_pm_add_addr * mptcp_pm_del_add_timer(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool check_id) { struct sock *sk = (struct sock *)msk; - struct mptcp_pm_add_entry *entry; + struct mptcp_pm_add_addr *entry; struct timer_list *timer = NULL; rcu_read_lock(); @@ -XXX,XX +XXX,XX @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { - struct mptcp_pm_add_entry *add_entry = NULL; + struct mptcp_pm_add_addr *add_entry = NULL; struct sock *sk = (struct sock *)msk; unsigned int timeout; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, static void mptcp_pm_free_anno_list(struct mptcp_sock *msk) { - struct mptcp_pm_add_entry *entry, *tmp; + struct mptcp_pm_add_addr *entry, *tmp; struct sock *sk = (struct sock *)msk; LIST_HEAD(free_list); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk, bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk); -struct mptcp_pm_add_entry * +struct mptcp_pm_add_addr * mptcp_pm_del_add_timer(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool check_id); bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, -- 2.53.0
Similar to the previous commit, only using the 'add' or 'anno' prefixes is confusing -- generally associated to the action of adding something, or the Latin name for "year" -- and lack of uniformity. This has been causing issues in the past, e.g. del_add_timer seemed to suggest the goal is to delete a previously added timer. Instead, use the mptcp_pm_announced_ prefix. While at it, slightly improves some helpers: - mptcp_lookup_anno_list_by_saddr: no need to specify what is used to do the lookup: mptcp_pm_announced_lookup. - mptcp_pm_sport_in_anno_list: it doesn't just compare the port, but the whole address linked to the sublow: mptcp_pm_announced_has_ssk. - mptcp_pm_alloc_anno_list: it allocates one item of the list, not a whole list: mptcp_pm_announced_alloc. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: also update comment mentioning mptcp_pm_announced_del_timer. --- net/mptcp/options.c | 2 +- net/mptcp/pm.c | 35 +++++++++++++++++------------------ net/mptcp/pm_kernel.c | 10 +++++----- net/mptcp/pm_userspace.c | 4 ++-- net/mptcp/protocol.h | 12 ++++++------ net/mptcp/subflow.c | 4 ++-- 6 files changed, 33 insertions(+), 34 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR); } else { mptcp_pm_add_addr_echoed(msk, &mp_opt.addr); - mptcp_pm_del_add_timer(msk, &mp_opt.addr, true); + mptcp_pm_announced_del_timer(msk, &mp_opt.addr, true); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD); } diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, } static struct mptcp_pm_add_addr * -mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, - const struct mptcp_addr_info *addr) +mptcp_pm_announced_lookup(const struct mptcp_sock *msk, + const struct mptcp_addr_info *addr) { struct mptcp_pm_add_addr *entry; @@ -XXX,XX +XXX,XX @@ mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, return NULL; } -bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr) +bool mptcp_pm_announced_remove(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr) { struct mptcp_pm_add_addr *entry; bool ret; - entry = mptcp_pm_del_add_timer(msk, addr, false); + entry = mptcp_pm_announced_del_timer(msk, addr, false); ret = entry; kfree_rcu(entry, rcu); return ret; } -bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk) +bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *ssk) { struct mptcp_pm_add_addr *entry; struct mptcp_addr_info saddr; bool ret = false; - mptcp_local_address((struct sock_common *)sk, &saddr); + mptcp_local_address((struct sock_common *)ssk, &saddr); spin_lock_bh(&msk->pm.lock); list_for_each_entry(entry, &msk->pm.anno_list, list) { @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_timer(struct timer_list *timer) spin_lock_bh(&msk->pm.lock); - /* The cancel path (mptcp_pm_del_add_timer()) can race with this + /* The cancel path (mptcp_pm_announced_del_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. @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_timer(struct timer_list *timer) } struct mptcp_pm_add_addr * -mptcp_pm_del_add_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id) +mptcp_pm_announced_del_timer(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr, bool check_id) { struct sock *sk = (struct sock *)msk; struct mptcp_pm_add_addr *entry; @@ -XXX,XX +XXX,XX @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, rcu_read_lock(); spin_lock_bh(&msk->pm.lock); - entry = mptcp_lookup_anno_list_by_saddr(msk, addr); + entry = mptcp_pm_announced_lookup(msk, addr); if (entry && (!check_id || entry->addr.id == addr->id)) { entry->retrans_times = ADD_ADDR_RETRANS_MAX; timer = &entry->add_timer; @@ -XXX,XX +XXX,XX @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, return entry; } -bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, +bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { struct mptcp_pm_add_addr *add_entry = NULL; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, lockdep_assert_held(&msk->pm.lock); - add_entry = mptcp_lookup_anno_list_by_saddr(msk, addr); - + add_entry = mptcp_pm_announced_lookup(msk, addr); if (add_entry) { if (WARN_ON_ONCE(mptcp_pm_is_kernel(msk))) return false; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, return true; } -static void mptcp_pm_free_anno_list(struct mptcp_sock *msk) +static void mptcp_pm_free_announced_list(struct mptcp_sock *msk) { struct mptcp_pm_add_addr *entry, *tmp; struct sock *sk = (struct sock *)msk; @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, spin_lock_bh(&pm->lock); - if (mptcp_lookup_anno_list_by_saddr(msk, addr) && READ_ONCE(pm->work_pending)) + if (mptcp_pm_announced_lookup(msk, addr) && READ_ONCE(pm->work_pending)) mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED); spin_unlock_bh(&pm->lock); @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, * let the PM state machine progress. */ if (skip_add_addr) { - mptcp_pm_del_add_timer(msk, addr, true); + mptcp_pm_announced_del_timer(msk, addr, true); mptcp_pm_subflow_established(msk); } return ret; @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_ops_release(struct mptcp_sock *msk) void mptcp_pm_destroy(struct mptcp_sock *msk) { - mptcp_pm_free_anno_list(msk); + mptcp_pm_free_announced_list(msk); mptcp_pm_ops_release(msk); } diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) /* If the alloc fails, we are on memory pressure, not worth * continuing, and trying to create subflows. */ - if (!mptcp_pm_alloc_anno_list(msk, &local.addr)) + if (!mptcp_pm_announced_alloc(msk, &local.addr)) return; __clear_bit(endp_id, msk->pm.id_avail_bitmap); @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_add_addr_doit(struct sk_buff *skb, struct genl_info *info) return ret; } -static void mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, +static void mptcp_pm_remove_announced(struct mptcp_sock *msk, const struct mptcp_addr_info *addr, bool force) { @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, list.ids[list.nr++] = mptcp_endp_get_local_id(msk, addr); - announced = mptcp_remove_anno_list_by_saddr(msk, addr); + announced = mptcp_pm_announced_remove(msk, addr); if (announced || force) { spin_lock_bh(&msk->pm.lock); if (announced) @@ -XXX,XX +XXX,XX @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net, lock_sock(sk); remove_subflow = mptcp_pm_has_subflow_saddr(msk, addr); - mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && + mptcp_pm_remove_announced(msk, addr, remove_subflow && !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); list.ids[0] = mptcp_endp_get_local_id(msk, addr); @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk, if (mptcp_pm_has_subflow_saddr(msk, &entry->addr)) slist.ids[slist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); - if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) + if (mptcp_pm_announced_remove(msk, &entry->addr)) alist.ids[alist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); if (slist.nr == MPTCP_RM_IDS_MAX || diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -XXX,XX +XXX,XX @@ int mptcp_pm_nl_announce_doit(struct sk_buff *skb, struct genl_info *info) lock_sock(sk); spin_lock_bh(&msk->pm.lock); - if (mptcp_pm_alloc_anno_list(msk, &addr_val.addr)) { + if (mptcp_pm_announced_alloc(msk, &addr_val.addr)) { msk->pm.add_addr_signaled++; mptcp_pm_announce_addr(msk, &addr_val.addr, false); mptcp_pm_addr_send_ack(msk); @@ -XXX,XX +XXX,XX @@ void mptcp_pm_remove_addr_entry(struct mptcp_sock *msk, int anno_nr = 0; /* only delete if either announced or matching a subflow */ - if (mptcp_remove_anno_list_by_saddr(msk, &entry->addr)) + if (mptcp_pm_announced_remove(msk, &entry->addr)) anno_nr++; else if (!mptcp_pm_has_subflow_saddr(msk, &entry->addr)) return; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk, struct mptcp_addr_info *addr, struct mptcp_addr_info *rem, u8 bkup); -bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, +bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); -bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk); struct mptcp_pm_add_addr * -mptcp_pm_del_add_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id); +mptcp_pm_announced_del_timer(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr, bool check_id); +bool mptcp_pm_announced_remove(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr); +bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *ssk); bool mptcp_pm_has_subflow_saddr(const struct mptcp_sock *msk, const struct mptcp_addr_info *saddr); -bool mptcp_remove_anno_list_by_saddr(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr); int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local, struct genl_info *info); int mptcp_userspace_pm_set_flags(struct mptcp_pm_addr_entry *local, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -XXX,XX +XXX,XX @@ static int subflow_check_req(struct request_sock *req, pr_debug("syn inet_sport=%d %d\n", ntohs(inet_sk(sk_listener)->inet_sport), ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport)); - if (!mptcp_pm_sport_in_anno_list(subflow_req->msk, sk_listener)) { + if (!mptcp_pm_announced_has_ssk(subflow_req->msk, sk_listener)) { SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX); subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT); return -EPERM; @@ -XXX,XX +XXX,XX @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, pr_debug("ack inet_sport=%d %d\n", ntohs(inet_sk(sk)->inet_sport), ntohs(inet_sk((struct sock *)owner)->inet_sport)); - if (!mptcp_pm_sport_in_anno_list(owner, sk)) { + if (!mptcp_pm_announced_has_ssk(owner, sk)) { SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTACKRX); subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT); goto dispose_child; -- 2.53.0
Similar to the two previous commits, using the 'add' prefix is confusing, also confirmed by [1]. Now that the structure has been renamed to include 'add_addr' in its name, easier to know the timer is linked to the ADD_ADDR, no need to add the confusing prefix, or an unneeded longer one. While at it, also update the ADD_ADDR timer helper to clearly specify it is linked to ADD_ADDR, and it is not there to add a new timer. Link: https://lore.kernel.org/20251117100745.1913963-1-edumazet@google.com [1] Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ struct mptcp_pm_add_addr { struct mptcp_addr_info addr; u8 retrans_times; bool timer_done; - struct timer_list add_timer; + struct timer_list timer; struct mptcp_sock *sock; struct rcu_head rcu; }; @@ -XXX,XX +XXX,XX @@ static unsigned int mptcp_adjust_add_addr_timeout(struct mptcp_sock *msk) return rto; } -static void mptcp_pm_add_timer(struct timer_list *timer) +static void mptcp_pm_add_addr_timer(struct timer_list *timer) { struct mptcp_pm_add_addr *entry = timer_container_of(entry, timer, - add_timer); + timer); struct mptcp_sock *msk = entry->sock; struct sock *sk = (struct sock *)msk; unsigned int timeout = 0; @@ -XXX,XX +XXX,XX @@ mptcp_pm_announced_del_timer(struct mptcp_sock *msk, entry = mptcp_pm_announced_lookup(msk, addr); if (entry && (!check_id || entry->addr.id == addr->id)) { entry->retrans_times = ADD_ADDR_RETRANS_MAX; - timer = &entry->add_timer; + timer = &entry->timer; } if (!check_id && entry) list_del(&entry->list); @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, add_entry->sock = msk; add_entry->retrans_times = 0; - timer_setup(&add_entry->add_timer, mptcp_pm_add_timer, 0); + timer_setup(&add_entry->timer, mptcp_pm_add_addr_timer, 0); reset_timer: add_entry->timer_done = false; timeout = mptcp_adjust_add_addr_timeout(msk); if (timeout) - sk_reset_timer(sk, &add_entry->add_timer, jiffies + timeout); + sk_reset_timer(sk, &add_entry->timer, jiffies + timeout); return true; } @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_free_announced_list(struct mptcp_sock *msk) list_for_each_entry_safe(entry, tmp, &free_list, list) { if (!entry->timer_done) - sk_stop_timer_sync(sk, &entry->add_timer); + sk_stop_timer_sync(sk, &entry->timer); kfree_rcu(entry, rcu); } } -- 2.53.0
Only used in pm.c. Note that the signature is added above: it is easier than moving the code around, because this helper depends on mptcp_pm_schedule_work which is declared below. While at it, explicitly mark it as to be called while pm->lock is held. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/pm.c | 4 +++- net/mptcp/protocol.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ static bool subflow_in_rm_list(const struct mptcp_subflow_context *subflow, return false; } +static void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk); static void mptcp_pm_addr_send_ack_avoid_list(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list) @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, spin_unlock_bh(&pm->lock); } -void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk) +/* To be called while pm->lock is held */ +static void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk) { if (!mptcp_pm_should_add_signal(msk)) return; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_received(const struct sock *ssk, const struct mptcp_addr_info *addr); void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); -void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk); void mptcp_pm_send_ack(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, bool prio, bool backup); -- 2.53.0
mptcp_pm_announced_del_timer() removes the matched ADD_ADDR entry (if found) from the ADD_ADDR list only if check_id is false. That's dangerous, and not clear, because it means the caller should be free the entry only in some cases, and it easy to miss that. Instead, make it static, and call it from mptcp_pm_add_addr_echoed, which is the only other case where mptcp_pm_add_addr_del_timer should be called with check_id set to true. Bonus with that: a second call to mptcp_pm_add_addr_lookup_by_addr() can be avoided. Note that instead of adding the signature above to avoid a compilation issue because this helper is called before the definition of the function, the whole helper is moved above where it is first called. Its content is untouched, except the addition of the 'static' keyboard. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- net/mptcp/options.c | 1 - net/mptcp/pm.c | 75 +++++++++++++++++++++++++++------------------------- net/mptcp/protocol.h | 3 --- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -XXX,XX +XXX,XX @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR); } else { mptcp_pm_add_addr_echoed(msk, &mp_opt.addr); - mptcp_pm_announced_del_timer(msk, &mp_opt.addr, true); MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD); } diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ mptcp_pm_announced_lookup(const struct mptcp_sock *msk, return NULL; } +static struct mptcp_pm_add_addr * +mptcp_pm_announced_del_timer(struct mptcp_sock *msk, + const struct mptcp_addr_info *addr, bool check_id) +{ + struct sock *sk = (struct sock *)msk; + struct mptcp_pm_add_addr *entry; + struct timer_list *timer = NULL; + + rcu_read_lock(); + + spin_lock_bh(&msk->pm.lock); + entry = mptcp_pm_announced_lookup(msk, addr); + if (entry && (!check_id || entry->addr.id == addr->id)) { + entry->retrans_times = ADD_ADDR_RETRANS_MAX; + timer = &entry->timer; + } + if (!check_id && entry) + list_del(&entry->list); + spin_unlock_bh(&msk->pm.lock); + + /* Note: entry might have been removed by another thread. + * We hold rcu_read_lock() to ensure it is not freed under us. + */ + if (timer && check_id) + sk_stop_timer(sk, timer); + + rcu_read_unlock(); + + if (timer && !check_id) + sk_stop_timer_sync(sk, timer); + + return entry; +} + bool mptcp_pm_announced_remove(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { @@ -XXX,XX +XXX,XX @@ static void mptcp_pm_add_addr_timer(struct timer_list *timer) sock_put(sk); } -struct mptcp_pm_add_addr * -mptcp_pm_announced_del_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id) -{ - struct sock *sk = (struct sock *)msk; - struct mptcp_pm_add_addr *entry; - struct timer_list *timer = NULL; - - rcu_read_lock(); - - spin_lock_bh(&msk->pm.lock); - entry = mptcp_pm_announced_lookup(msk, addr); - if (entry && (!check_id || entry->addr.id == addr->id)) { - entry->retrans_times = ADD_ADDR_RETRANS_MAX; - timer = &entry->timer; - } - if (!check_id && entry) - list_del(&entry->list); - spin_unlock_bh(&msk->pm.lock); - - /* Note: entry might have been removed by another thread. - * We hold rcu_read_lock() to ensure it is not freed under us. - */ - if (timer && check_id) - sk_stop_timer(sk, timer); - - rcu_read_unlock(); - - if (timer && !check_id) - sk_stop_timer_sync(sk, timer); - - return entry; -} - bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, const struct mptcp_addr_info *addr) { struct mptcp_pm_data *pm = &msk->pm; + struct mptcp_pm_add_addr *entry; pr_debug("msk=%p\n", msk); - if (!READ_ONCE(pm->work_pending)) + entry = mptcp_pm_announced_del_timer(msk, addr, true); + + if (!entry || !READ_ONCE(pm->work_pending)) return; spin_lock_bh(&pm->lock); - if (mptcp_pm_announced_lookup(msk, addr) && READ_ONCE(pm->work_pending)) + if (READ_ONCE(pm->work_pending)) mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED); spin_unlock_bh(&pm->lock); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -XXX,XX +XXX,XX @@ int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk, u8 bkup); bool mptcp_pm_announced_alloc(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); -struct mptcp_pm_add_addr * -mptcp_pm_announced_del_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id); bool mptcp_pm_announced_remove(struct mptcp_sock *msk, const struct mptcp_addr_info *addr); bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *ssk); -- 2.53.0
We an always check the ID in mptcp_pm_announced_del_timer: this check is needed when an echo is received, but in other cases, the caller will use an entry that was previously added in the list, so they have to match too, otherwise that's not correct. After having removed this extra check, the variable is only used to know what to do with the list and the timer. Use del_list instead of check_id: clearer that the action will remove the entry from the list. Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org> --- v2: fix typo (check_id -> !del_list, '!' was missing in one case) --- net/mptcp/pm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index XXXXXXX..XXXXXXX 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -XXX,XX +XXX,XX @@ mptcp_pm_announced_lookup(const struct mptcp_sock *msk, static struct mptcp_pm_add_addr * mptcp_pm_announced_del_timer(struct mptcp_sock *msk, - const struct mptcp_addr_info *addr, bool check_id) + const struct mptcp_addr_info *addr, bool del_list) { struct sock *sk = (struct sock *)msk; struct mptcp_pm_add_addr *entry; @@ -XXX,XX +XXX,XX @@ mptcp_pm_announced_del_timer(struct mptcp_sock *msk, spin_lock_bh(&msk->pm.lock); entry = mptcp_pm_announced_lookup(msk, addr); - if (entry && (!check_id || entry->addr.id == addr->id)) { + if (entry && entry->addr.id == addr->id) { entry->retrans_times = ADD_ADDR_RETRANS_MAX; timer = &entry->timer; } - if (!check_id && entry) + if (del_list && entry) list_del(&entry->list); spin_unlock_bh(&msk->pm.lock); /* Note: entry might have been removed by another thread. * We hold rcu_read_lock() to ensure it is not freed under us. */ - if (timer && check_id) + if (timer && !del_list) sk_stop_timer(sk, timer); rcu_read_unlock(); - if (timer && !check_id) + if (timer && del_list) sk_stop_timer_sync(sk, timer); return entry; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_announced_remove(struct mptcp_sock *msk, struct mptcp_pm_add_addr *entry; bool ret; - entry = mptcp_pm_announced_del_timer(msk, addr, false); + entry = mptcp_pm_announced_del_timer(msk, addr, true); ret = entry; kfree_rcu(entry, rcu); @@ -XXX,XX +XXX,XX @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk, pr_debug("msk=%p\n", msk); - entry = mptcp_pm_announced_del_timer(msk, addr, true); + entry = mptcp_pm_announced_del_timer(msk, addr, false); if (!entry || !READ_ONCE(pm->work_pending)) return; @@ -XXX,XX +XXX,XX @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, * let the PM state machine progress. */ if (skip_add_addr) { - mptcp_pm_announced_del_timer(msk, addr, true); + mptcp_pm_announced_del_timer(msk, addr, false); mptcp_pm_subflow_established(msk); } return ret; -- 2.53.0