Commit 3980cf16 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'mptcp-more-misc-fixes-for-v6-8'

Matthieu Baerts says:

====================
mptcp: more misc. fixes for v6.8

This series includes 6 types of fixes:

- Patch 1 fixes v4 mapped in v6 addresses support for the userspace PM,
  when asking to delete a subflow. It was done everywhere else, but not
  there. Patch 2 validates the modification, thanks to a subtest in
  mptcp_join.sh. These patches can be backported up to v5.19.

- Patch 3 is a small fix for a recent bug-fix patch, just to avoid
  printing an irrelevant warning (pr_warn()) once. It can be backported
  up to v5.6, alongside the bug-fix that has been introduced in the
  v6.8-rc5.

- Patches 4 to 6 are fixes for bugs found by Paolo while working on
  TCP_NOTSENT_LOWAT support for MPTCP. These fixes can improve the
  performances in some cases. Patches can be backported up to v5.6,
  v5.11 and v6.7 respectively.

- Patch 7 makes sure 'ss -M' is available when starting MPTCP Join
  selftest as it is required for some subtests since v5.18.

- Patch 8 fixes a possible double-free on socket dismantle. The issue
  always existed, but was unnoticed because it was not causing any
  problem so far. This fix can be backported up to v5.6.

- Patch 9 is a fix for a very recent patch causing lockdep warnings in
  subflow diag. The patch causing the regression -- which fixes another
  issue present since v5.7 -- should be part of the future v6.8-rc6.
  Patch 10 validates the modification, thanks to a new subtest in
  diag.sh.
====================

Link: https://lore.kernel.org/r/20240223-upstream-net-20240223-misc-fixes-v1-0-162e87e48497@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 0d60d8df b4b51d36
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ static int subflow_get_info(struct sock *sk, struct sk_buff *skb)
	bool slow;
	int err;

	if (inet_sk_state_load(sk) == TCP_LISTEN)
		return 0;

	start = nla_nest_start_noflag(skb, INET_ULP_INFO_MPTCP);
	if (!start)
		return -EMSGSIZE;
+1 −1
Original line number Diff line number Diff line
@@ -981,10 +981,10 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
	if (mp_opt->deny_join_id0)
		WRITE_ONCE(msk->pm.remote_deny_join_id0, true);

set_fully_established:
	if (unlikely(!READ_ONCE(msk->pm.server_side)))
		pr_warn_once("bogus mpc option on established client sk");

set_fully_established:
	mptcp_data_lock((struct sock *)msk);
	__mptcp_subflow_fully_established(msk, subflow, mp_opt);
	mptcp_data_unlock((struct sock *)msk);
+10 −0
Original line number Diff line number Diff line
@@ -495,6 +495,16 @@ int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info
		goto destroy_err;
	}

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
	if (addr_l.family == AF_INET && ipv6_addr_v4mapped(&addr_r.addr6)) {
		ipv6_addr_set_v4mapped(addr_l.addr.s_addr, &addr_l.addr6);
		addr_l.family = AF_INET6;
	}
	if (addr_r.family == AF_INET && ipv6_addr_v4mapped(&addr_l.addr6)) {
		ipv6_addr_set_v4mapped(addr_r.addr.s_addr, &addr_r.addr6);
		addr_r.family = AF_INET6;
	}
#endif
	if (addr_l.family != addr_r.family) {
		GENL_SET_ERR_MSG(info, "address families do not match");
		err = -EINVAL;
+51 −1
Original line number Diff line number Diff line
@@ -1260,6 +1260,7 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
		mpext = mptcp_get_ext(skb);
		if (!mptcp_skb_can_collapse_to(data_seq, skb, mpext)) {
			TCP_SKB_CB(skb)->eor = 1;
			tcp_mark_push(tcp_sk(ssk), skb);
			goto alloc_skb;
		}

@@ -3177,8 +3178,50 @@ static struct ipv6_pinfo *mptcp_inet6_sk(const struct sock *sk)

	return (struct ipv6_pinfo *)(((u8 *)sk) + offset);
}

static void mptcp_copy_ip6_options(struct sock *newsk, const struct sock *sk)
{
	const struct ipv6_pinfo *np = inet6_sk(sk);
	struct ipv6_txoptions *opt;
	struct ipv6_pinfo *newnp;

	newnp = inet6_sk(newsk);

	rcu_read_lock();
	opt = rcu_dereference(np->opt);
	if (opt) {
		opt = ipv6_dup_options(newsk, opt);
		if (!opt)
			net_warn_ratelimited("%s: Failed to copy ip6 options\n", __func__);
	}
	RCU_INIT_POINTER(newnp->opt, opt);
	rcu_read_unlock();
}
#endif

static void mptcp_copy_ip_options(struct sock *newsk, const struct sock *sk)
{
	struct ip_options_rcu *inet_opt, *newopt = NULL;
	const struct inet_sock *inet = inet_sk(sk);
	struct inet_sock *newinet;

	newinet = inet_sk(newsk);

	rcu_read_lock();
	inet_opt = rcu_dereference(inet->inet_opt);
	if (inet_opt) {
		newopt = sock_kmalloc(newsk, sizeof(*inet_opt) +
				      inet_opt->opt.optlen, GFP_ATOMIC);
		if (newopt)
			memcpy(newopt, inet_opt, sizeof(*inet_opt) +
			       inet_opt->opt.optlen);
		else
			net_warn_ratelimited("%s: Failed to copy ip options\n", __func__);
	}
	RCU_INIT_POINTER(newinet->inet_opt, newopt);
	rcu_read_unlock();
}

struct sock *mptcp_sk_clone_init(const struct sock *sk,
				 const struct mptcp_options_received *mp_opt,
				 struct sock *ssk,
@@ -3199,6 +3242,13 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,

	__mptcp_init_sock(nsk);

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
	if (nsk->sk_family == AF_INET6)
		mptcp_copy_ip6_options(nsk, sk);
	else
#endif
		mptcp_copy_ip_options(nsk, sk);

	msk = mptcp_sk(nsk);
	msk->local_key = subflow_req->local_key;
	msk->token = subflow_req->token;
@@ -3210,7 +3260,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
	msk->write_seq = subflow_req->idsn + 1;
	msk->snd_nxt = msk->write_seq;
	msk->snd_una = msk->write_seq;
	msk->wnd_end = msk->snd_nxt + req->rsk_rcv_wnd;
	msk->wnd_end = msk->snd_nxt + tcp_sk(ssk)->snd_wnd;
	msk->setsockopt_seq = mptcp_sk(sk)->setsockopt_seq;
	mptcp_init_sched(msk, mptcp_sk(sk)->sched);

+11 −10
Original line number Diff line number Diff line
@@ -790,6 +790,16 @@ static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk)
	       READ_ONCE(msk->write_seq) == READ_ONCE(msk->snd_nxt);
}

static inline void mptcp_write_space(struct sock *sk)
{
	if (sk_stream_is_writeable(sk)) {
		/* pairs with memory barrier in mptcp_poll */
		smp_mb();
		if (test_and_clear_bit(MPTCP_NOSPACE, &mptcp_sk(sk)->flags))
			sk_stream_write_space(sk);
	}
}

static inline void __mptcp_sync_sndbuf(struct sock *sk)
{
	struct mptcp_subflow_context *subflow;
@@ -808,6 +818,7 @@ static inline void __mptcp_sync_sndbuf(struct sock *sk)

	/* the msk max wmem limit is <nr_subflows> * tcp wmem[2] */
	WRITE_ONCE(sk->sk_sndbuf, new_sndbuf);
	mptcp_write_space(sk);
}

/* The called held both the msk socket and the subflow socket locks,
@@ -838,16 +849,6 @@ static inline void mptcp_propagate_sndbuf(struct sock *sk, struct sock *ssk)
	local_bh_enable();
}

static inline void mptcp_write_space(struct sock *sk)
{
	if (sk_stream_is_writeable(sk)) {
		/* pairs with memory barrier in mptcp_poll */
		smp_mb();
		if (test_and_clear_bit(MPTCP_NOSPACE, &mptcp_sk(sk)->flags))
			sk_stream_write_space(sk);
	}
}

void mptcp_destroy_common(struct mptcp_sock *msk, unsigned int flags);

#define MPTCP_TOKEN_MAX_RETRIES	4
Loading