Commit ca1a6705 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mptcp-next'



Mat Martineau says:

====================
mptcp: New features and cleanup

These patches have been tested in the MPTCP tree for a longer than usual
time (thanks to holiday schedules), and are ready for the net-next
branch. Changes include feature updates, small fixes, refactoring, and
some selftest changes.

Patch 1 fixes an OUTQ ioctl issue with TCP fallback sockets.

Patches 2, 3, and 6 add support of the MPTCP fastclose option (quick
shutdown of the full MPTCP connection, similar to TCP RST in regular
TCP), and a related self test.

Patch 4 cleans up some accept and poll code that is no longer needed
after the fastclose changes.

Patch 5 add userspace disconnect using AF_UNSPEC, which is used when
testing fastclose and makes the MPTCP socket's handling of AF_UNSPEC in
connect() more TCP-like.

Patches 7-11 refactor subflow creation to make better use of multiple
local endpoints and to better handle individual connection failures when
creating multiple subflows. Includes self test updates.

Patch 12 cleans up the way subflows are added to the MPTCP connection
list, eliminating the need for calls throughout the MPTCP code that had
to check the intermediate "join list" for entries to shift over to the
main "connection list".

Patch 13 refactors the MPTCP release_cb flags to use separate storage
for values only accessed with the socket lock held (no atomic ops
needed), and for values that need atomic operations.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 26abf15c e9d09bac
Loading
Loading
Loading
Loading
+68 −33
Original line number Diff line number Diff line
@@ -768,6 +768,28 @@ 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,
						unsigned int remaining,
						struct mptcp_out_options *opts)
{
	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
	struct mptcp_sock *msk = mptcp_sk(subflow->conn);

	if (likely(!subflow->send_fastclose))
		return false;

	if (remaining < TCPOLEN_MPTCP_FASTCLOSE)
		return false;

	*size = TCPOLEN_MPTCP_FASTCLOSE;
	opts->suboptions |= OPTION_MPTCP_FASTCLOSE;
	opts->rcvr_key = msk->remote_key;

	pr_debug("FASTCLOSE key=%llu", opts->rcvr_key);
	return true;
}

static bool mptcp_established_options_mp_fail(struct sock *sk,
					      unsigned int *size,
					      unsigned int remaining,
@@ -806,10 +828,12 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
		return false;

	if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) {
		if (mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) {
		if (mptcp_established_options_fastclose(sk, &opt_size, remaining, opts) ||
		    mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) {
			*size += opt_size;
			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)) {
			*size += opt_size;
			remaining -= opt_size;
@@ -1251,17 +1275,8 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
		ptr += 2;
	}

	/* RST is mutually exclusive with everything else */
	if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) {
		*ptr++ = mptcp_option(MPTCPOPT_RST,
				      TCPOLEN_MPTCP_RST,
				      opts->reset_transient,
				      opts->reset_reason);
		return;
	}

	/* DSS, MPC, MPJ and ADD_ADDR are mutually exclusive, see
	 * mptcp_established_options*()
	/* DSS, MPC, MPJ, ADD_ADDR, FASTCLOSE and RST are mutually exclusive,
	 * see mptcp_established_options*()
	 */
	if (likely(OPTION_MPTCP_DSS & opts->suboptions)) {
		struct mptcp_ext *mpext = &opts->ext_copy;
@@ -1370,7 +1385,8 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,

		/* MPC is additionally mutually exclusive with MP_PRIO */
		goto mp_capable_done;
	} else if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) {
	} else if (OPTIONS_MPTCP_MPJ & opts->suboptions) {
		if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) {
			*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
					      TCPOLEN_MPTCP_MPJ_SYN,
					      opts->backup, opts->join_id);
@@ -1386,11 +1402,12 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
			ptr += 2;
			put_unaligned_be32(opts->nonce, ptr);
			ptr += 1;
	} else if (OPTION_MPTCP_MPJ_ACK & opts->suboptions) {
		} else {
			*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
					      TCPOLEN_MPTCP_MPJ_ACK, 0, 0);
			memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN);
			ptr += 5;
		}
	} else if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
		u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
		u8 echo = MPTCP_ADDR_ECHO;
@@ -1447,6 +1464,24 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
				ptr += 1;
			}
		}
	} else if (unlikely(OPTION_MPTCP_FASTCLOSE & opts->suboptions)) {
		/* FASTCLOSE is mutually exclusive with others except RST */
		*ptr++ = mptcp_option(MPTCPOPT_MP_FASTCLOSE,
				      TCPOLEN_MPTCP_FASTCLOSE,
				      0, 0);
		put_unaligned_be64(opts->rcvr_key, ptr);
		ptr += 2;

		if (OPTION_MPTCP_RST & opts->suboptions)
			goto mp_rst;
		return;
	} else if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) {
mp_rst:
		*ptr++ = mptcp_option(MPTCPOPT_RST,
				      TCPOLEN_MPTCP_RST,
				      opts->reset_transient,
				      opts->reset_reason);
		return;
	}

	if (OPTION_MPTCP_PRIO & opts->suboptions) {
+29 −5
Original line number Diff line number Diff line
@@ -172,9 +172,28 @@ void mptcp_pm_subflow_established(struct mptcp_sock *msk)
	spin_unlock_bh(&pm->lock);
}

void mptcp_pm_subflow_closed(struct mptcp_sock *msk, u8 id)
void mptcp_pm_subflow_check_next(struct mptcp_sock *msk, const struct sock *ssk,
				 const struct mptcp_subflow_context *subflow)
{
	pr_debug("msk=%p", msk);
	struct mptcp_pm_data *pm = &msk->pm;
	bool update_subflows;

	update_subflows = (ssk->sk_state == TCP_CLOSE) &&
			  (subflow->request_join || subflow->mp_join);
	if (!READ_ONCE(pm->work_pending) && !update_subflows)
		return;

	spin_lock_bh(&pm->lock);
	if (update_subflows)
		pm->subflows--;

	/* Even if this subflow is not really established, tell the PM to try
	 * to pick the next ones, if possible.
	 */
	if (mptcp_pm_nl_check_work_pending(msk))
		mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED);

	spin_unlock_bh(&pm->lock);
}

void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
@@ -356,7 +375,7 @@ void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk)
	}
}

void mptcp_pm_data_init(struct mptcp_sock *msk)
void mptcp_pm_data_reset(struct mptcp_sock *msk)
{
	msk->pm.add_addr_signaled = 0;
	msk->pm.add_addr_accepted = 0;
@@ -370,11 +389,16 @@ void mptcp_pm_data_init(struct mptcp_sock *msk)
	WRITE_ONCE(msk->pm.accept_subflow, false);
	WRITE_ONCE(msk->pm.remote_deny_join_id0, false);
	msk->pm.status = 0;
	bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);

	mptcp_pm_nl_data_init(msk);
}

void mptcp_pm_data_init(struct mptcp_sock *msk)
{
	spin_lock_init(&msk->pm.lock);
	INIT_LIST_HEAD(&msk->pm.anno_list);

	mptcp_pm_nl_data_init(msk);
	mptcp_pm_data_reset(msk);
}

void __init mptcp_pm_init(void)
+118 −79
Original line number Diff line number Diff line
@@ -38,10 +38,6 @@ struct mptcp_pm_add_entry {
	u8			retrans_times;
};

/* max value of mptcp_addr_info.id */
#define MAX_ADDR_ID		U8_MAX
#define BITMAP_SZ DIV_ROUND_UP(MAX_ADDR_ID + 1, BITS_PER_LONG)

struct pm_nl_pernet {
	/* protects pernet updates */
	spinlock_t		lock;
@@ -53,14 +49,14 @@ struct pm_nl_pernet {
	unsigned int		local_addr_max;
	unsigned int		subflows_max;
	unsigned int		next_id;
	unsigned long		id_bitmap[BITMAP_SZ];
	DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
};

#define MPTCP_PM_ADDR_MAX	8
#define ADD_ADDR_RETRANS_MAX	3

static bool addresses_equal(const struct mptcp_addr_info *a,
			    struct mptcp_addr_info *b, bool use_port)
			    const struct mptcp_addr_info *b, bool use_port)
{
	bool addr_equals = false;

@@ -169,11 +165,13 @@ select_local_address(const struct pm_nl_pernet *pernet,
	msk_owned_by_me(msk);

	rcu_read_lock();
	__mptcp_flush_join_list(msk);
	list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
		if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW))
			continue;

		if (!test_bit(entry->addr.id, msk->pm.id_avail_bitmap))
			continue;

		if (entry->addr.family != sk->sk_family) {
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
			if ((entry->addr.family == AF_INET &&
@@ -184,23 +182,17 @@ select_local_address(const struct pm_nl_pernet *pernet,
				continue;
		}

		/* avoid any address already in use by subflows and
		 * pending join
		 */
		if (!lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) {
		ret = entry;
		break;
	}
	}
	rcu_read_unlock();
	return ret;
}

static struct mptcp_pm_addr_entry *
select_signal_address(struct pm_nl_pernet *pernet, unsigned int pos)
select_signal_address(struct pm_nl_pernet *pernet, struct mptcp_sock *msk)
{
	struct mptcp_pm_addr_entry *entry, *ret = NULL;
	int i = 0;

	rcu_read_lock();
	/* do not keep any additional per socket state, just signal
@@ -209,13 +201,15 @@ select_signal_address(struct pm_nl_pernet *pernet, unsigned int pos)
	 * can lead to additional addresses not being announced.
	 */
	list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
		if (!test_bit(entry->addr.id, msk->pm.id_avail_bitmap))
			continue;

		if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
			continue;
		if (i++ == pos) {

		ret = entry;
		break;
	}
	}
	rcu_read_unlock();
	return ret;
}
@@ -256,12 +250,17 @@ unsigned int mptcp_pm_get_local_addr_max(struct mptcp_sock *msk)
}
EXPORT_SYMBOL_GPL(mptcp_pm_get_local_addr_max);

static void check_work_pending(struct mptcp_sock *msk)
bool mptcp_pm_nl_check_work_pending(struct mptcp_sock *msk)
{
	if (msk->pm.add_addr_signaled == mptcp_pm_get_add_addr_signal_max(msk) &&
	    (msk->pm.local_addr_used == mptcp_pm_get_local_addr_max(msk) ||
	     msk->pm.subflows == mptcp_pm_get_subflows_max(msk)))
	struct pm_nl_pernet *pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);

	if (msk->pm.subflows == mptcp_pm_get_subflows_max(msk) ||
	    (find_next_and_bit(pernet->id_bitmap, msk->pm.id_avail_bitmap,
			       MPTCP_PM_MAX_ADDR_ID + 1, 0) == MPTCP_PM_MAX_ADDR_ID + 1)) {
		WRITE_ONCE(msk->pm.work_pending, false);
		return false;
	}
	return true;
}

struct mptcp_pm_add_entry *
@@ -430,6 +429,7 @@ static bool lookup_address_in_vec(struct mptcp_addr_info *addrs, unsigned int nr
static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk, bool fullmesh,
					      struct mptcp_addr_info *addrs)
{
	bool deny_id0 = READ_ONCE(msk->pm.remote_deny_join_id0);
	struct sock *sk = (struct sock *)msk, *ssk;
	struct mptcp_subflow_context *subflow;
	struct mptcp_addr_info remote = { 0 };
@@ -437,22 +437,28 @@ static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk, bool fullm
	int i = 0;

	subflows_max = mptcp_pm_get_subflows_max(msk);
	remote_address((struct sock_common *)sk, &remote);

	/* Non-fullmesh endpoint, fill in the single entry
	 * corresponding to the primary MPC subflow remote address
	 */
	if (!fullmesh) {
		remote_address((struct sock_common *)sk, &remote);
		if (deny_id0)
			return 0;

		msk->pm.subflows++;
		addrs[i++] = remote;
	} else {
		mptcp_for_each_subflow(msk, subflow) {
			ssk = mptcp_subflow_tcp_sock(subflow);
			remote_address((struct sock_common *)ssk, &remote);
			if (!lookup_address_in_vec(addrs, i, &remote) &&
			remote_address((struct sock_common *)ssk, &addrs[i]);
			if (deny_id0 && addresses_equal(&addrs[i], &remote, false))
				continue;

			if (!lookup_address_in_vec(addrs, i, &addrs[i]) &&
			    msk->pm.subflows < subflows_max) {
				msk->pm.subflows++;
				addrs[i++] = remote;
				i++;
			}
		}
	}
@@ -460,6 +466,35 @@ static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk, bool fullm
	return i;
}

static struct mptcp_pm_addr_entry *
__lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id)
{
	struct mptcp_pm_addr_entry *entry;

	list_for_each_entry(entry, &pernet->local_addr_list, list) {
		if (entry->addr.id == id)
			return entry;
	}
	return NULL;
}

static int
lookup_id_by_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *addr)
{
	struct mptcp_pm_addr_entry *entry;
	int ret = -1;

	rcu_read_lock();
	list_for_each_entry(entry, &pernet->local_addr_list, list) {
		if (addresses_equal(&entry->addr, addr, entry->addr.port)) {
			ret = entry->addr.id;
			break;
		}
	}
	rcu_read_unlock();
	return ret;
}

static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
{
	struct sock *sk = (struct sock *)msk;
@@ -475,6 +510,19 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
	local_addr_max = mptcp_pm_get_local_addr_max(msk);
	subflows_max = mptcp_pm_get_subflows_max(msk);

	/* do lazy endpoint usage accounting for the MPC subflows */
	if (unlikely(!(msk->pm.status & BIT(MPTCP_PM_MPC_ENDPOINT_ACCOUNTED))) && msk->first) {
		struct mptcp_addr_info mpc_addr;
		int mpc_id;

		local_address((struct sock_common *)msk->first, &mpc_addr);
		mpc_id = lookup_id_by_addr(pernet, &mpc_addr);
		if (mpc_id >= 0)
			__clear_bit(mpc_id, msk->pm.id_avail_bitmap);

		msk->pm.status |= BIT(MPTCP_PM_MPC_ENDPOINT_ACCOUNTED);
	}

	pr_debug("local %d:%d signal %d:%d subflows %d:%d\n",
		 msk->pm.local_addr_used, local_addr_max,
		 msk->pm.add_addr_signaled, add_addr_signal_max,
@@ -482,47 +530,41 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)

	/* check first for announce */
	if (msk->pm.add_addr_signaled < add_addr_signal_max) {
		local = select_signal_address(pernet,
					      msk->pm.add_addr_signaled);
		local = select_signal_address(pernet, msk);

		if (local) {
			if (mptcp_pm_alloc_anno_list(msk, local)) {
				__clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
				msk->pm.add_addr_signaled++;
				mptcp_pm_announce_addr(msk, &local->addr, false);
				mptcp_pm_nl_addr_send_ack(msk);
			}
		} else {
			/* pick failed, avoid fourther attempts later */
			msk->pm.local_addr_used = add_addr_signal_max;
		}

		check_work_pending(msk);
	}

	/* check if should create a new subflow */
	if (msk->pm.local_addr_used < local_addr_max &&
	    msk->pm.subflows < subflows_max &&
	    !READ_ONCE(msk->pm.remote_deny_join_id0)) {
		local = select_local_address(pernet, msk);
		if (local) {
			bool fullmesh = !!(local->flags & MPTCP_PM_ADDR_FLAG_FULLMESH);
	while (msk->pm.local_addr_used < local_addr_max &&
	       msk->pm.subflows < subflows_max) {
		struct mptcp_addr_info addrs[MPTCP_PM_ADDR_MAX];
		bool fullmesh;
		int i, nr;

		local = select_local_address(pernet, msk);
		if (!local)
			break;

		fullmesh = !!(local->flags & MPTCP_PM_ADDR_FLAG_FULLMESH);

		msk->pm.local_addr_used++;
			check_work_pending(msk);
		nr = fill_remote_addresses_vec(msk, fullmesh, addrs);
		if (nr)
			__clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
		spin_unlock_bh(&msk->pm.lock);
		for (i = 0; i < nr; i++)
			__mptcp_subflow_connect(sk, &local->addr, &addrs[i]);
		spin_lock_bh(&msk->pm.lock);
			return;
		}

		/* lookup failed, avoid fourther attempts later */
		msk->pm.local_addr_used = local_addr_max;
		check_work_pending(msk);
	}
	mptcp_pm_nl_check_work_pending(msk);
}

static void mptcp_pm_nl_fully_established(struct mptcp_sock *msk)
@@ -552,7 +594,6 @@ static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk,
	subflows_max = mptcp_pm_get_subflows_max(msk);

	rcu_read_lock();
	__mptcp_flush_join_list(msk);
	list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
		if (!(entry->flags & MPTCP_PM_ADDR_FLAG_FULLMESH))
			continue;
@@ -641,7 +682,6 @@ void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk)
	    !mptcp_pm_should_rm_signal(msk))
		return;

	__mptcp_flush_join_list(msk);
	subflow = list_first_entry_or_null(&msk->conn_list, typeof(*subflow), node);
	if (subflow) {
		struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
@@ -711,6 +751,8 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
		return;

	for (i = 0; i < rm_list->nr; i++) {
		bool removed = false;

		list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
			struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
			int how = RCV_SHUTDOWN | SEND_SHUTDOWN;
@@ -727,18 +769,24 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
				 i, rm_list->ids[i], subflow->local_id, subflow->remote_id);
			spin_unlock_bh(&msk->pm.lock);
			mptcp_subflow_shutdown(sk, ssk, how);

			/* the following takes care of updating the subflows counter */
			mptcp_close_ssk(sk, ssk, subflow);
			spin_lock_bh(&msk->pm.lock);

			removed = true;
			__MPTCP_INC_STATS(sock_net(sk), rm_type);
		}
		__set_bit(rm_list->ids[1], msk->pm.id_avail_bitmap);
		if (!removed)
			continue;

		if (rm_type == MPTCP_MIB_RMADDR) {
			msk->pm.add_addr_accepted--;
			WRITE_ONCE(msk->pm.accept_addr, true);
		} else if (rm_type == MPTCP_MIB_RMSUBFLOW) {
			msk->pm.local_addr_used--;
		}
			msk->pm.subflows--;
			__MPTCP_INC_STATS(sock_net(sk), rm_type);
		}
	}
}

@@ -759,6 +807,9 @@ void mptcp_pm_nl_work(struct mptcp_sock *msk)

	msk_owned_by_me(msk);

	if (!(pm->status & MPTCP_PM_WORK_MASK))
		return;

	spin_lock_bh(&msk->pm.lock);

	pr_debug("msk=%p status=%x", msk, pm->status);
@@ -804,7 +855,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
	/* to keep the code simple, don't do IDR-like allocation for address ID,
	 * just bail when we exceed limits
	 */
	if (pernet->next_id == MAX_ADDR_ID)
	if (pernet->next_id == MPTCP_PM_MAX_ADDR_ID)
		pernet->next_id = 1;
	if (pernet->addrs >= MPTCP_PM_ADDR_MAX)
		goto out;
@@ -824,7 +875,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
	if (!entry->addr.id) {
find_next:
		entry->addr.id = find_next_zero_bit(pernet->id_bitmap,
						    MAX_ADDR_ID + 1,
						    MPTCP_PM_MAX_ADDR_ID + 1,
						    pernet->next_id);
		if (!entry->addr.id && pernet->next_id != 1) {
			pernet->next_id = 1;
@@ -1191,18 +1242,6 @@ static int mptcp_nl_cmd_add_addr(struct sk_buff *skb, struct genl_info *info)
	return 0;
}

static struct mptcp_pm_addr_entry *
__lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id)
{
	struct mptcp_pm_addr_entry *entry;

	list_for_each_entry(entry, &pernet->local_addr_list, list) {
		if (entry->addr.id == id)
			return entry;
	}
	return NULL;
}

int mptcp_pm_get_flags_and_ifindex_by_id(struct net *net, unsigned int id,
					 u8 *flags, int *ifindex)
{
@@ -1461,7 +1500,7 @@ static int mptcp_nl_cmd_flush_addrs(struct sk_buff *skb, struct genl_info *info)
	list_splice_init(&pernet->local_addr_list, &free_list);
	__reset_counters(pernet);
	pernet->next_id = 1;
	bitmap_zero(pernet->id_bitmap, MAX_ADDR_ID + 1);
	bitmap_zero(pernet->id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
	spin_unlock_bh(&pernet->lock);
	mptcp_nl_remove_addrs_list(sock_net(skb->sk), &free_list);
	synchronize_rcu();
@@ -1571,7 +1610,7 @@ static int mptcp_nl_cmd_dump_addrs(struct sk_buff *msg,
	pernet = net_generic(net, pm_nl_pernet_id);

	spin_lock_bh(&pernet->lock);
	for (i = id; i < MAX_ADDR_ID + 1; i++) {
	for (i = id; i < MPTCP_PM_MAX_ADDR_ID + 1; i++) {
		if (test_bit(i, pernet->id_bitmap)) {
			entry = __lookup_addr_by_id(pernet, i);
			if (!entry)
+174 −133

File changed.

Preview size limit exceeded, changes collapsed.

+41 −22
Original line number Diff line number Diff line
@@ -110,19 +110,20 @@
/* MPTCP TCPRST flags */
#define MPTCP_RST_TRANSIENT	BIT(0)

/* MPTCP socket flags */
#define MPTCP_DATA_READY	0
/* MPTCP socket atomic flags */
#define MPTCP_NOSPACE		1
#define MPTCP_WORK_RTX		2
#define MPTCP_WORK_EOF		3
#define MPTCP_FALLBACK_DONE	4
#define MPTCP_WORK_CLOSE_SUBFLOW 5
#define MPTCP_PUSH_PENDING	6
#define MPTCP_CLEAN_UNA		7
#define MPTCP_ERROR_REPORT	8
#define MPTCP_RETRANSMIT	9
#define MPTCP_WORK_SYNC_SETSOCKOPT 10
#define MPTCP_CONNECTED		11

/* MPTCP socket release cb flags */
#define MPTCP_PUSH_PENDING	1
#define MPTCP_CLEAN_UNA		2
#define MPTCP_ERROR_REPORT	3
#define MPTCP_RETRANSMIT	4
#define MPTCP_FLUSH_JOIN_LIST	5
#define MPTCP_CONNECTED		6

static inline bool before64(__u64 seq1, __u64 seq2)
{
@@ -174,16 +175,25 @@ enum mptcp_pm_status {
	MPTCP_PM_ADD_ADDR_SEND_ACK,
	MPTCP_PM_RM_ADDR_RECEIVED,
	MPTCP_PM_ESTABLISHED,
	MPTCP_PM_ALREADY_ESTABLISHED,	/* persistent status, set after ESTABLISHED event */
	MPTCP_PM_SUBFLOW_ESTABLISHED,
	MPTCP_PM_ALREADY_ESTABLISHED,	/* persistent status, set after ESTABLISHED event */
	MPTCP_PM_MPC_ENDPOINT_ACCOUNTED /* persistent status, set after MPC local address is
					 * accounted int id_avail_bitmap
					 */
};

/* Status bits below MPTCP_PM_ALREADY_ESTABLISHED need pm worker actions */
#define MPTCP_PM_WORK_MASK ((1 << MPTCP_PM_ALREADY_ESTABLISHED) - 1)

enum mptcp_addr_signal_status {
	MPTCP_ADD_ADDR_SIGNAL,
	MPTCP_ADD_ADDR_ECHO,
	MPTCP_RM_ADDR_SIGNAL,
};

/* max value of mptcp_addr_info.id */
#define MPTCP_PM_MAX_ADDR_ID		U8_MAX

struct mptcp_pm_data {
	struct mptcp_addr_info local;
	struct mptcp_addr_info remote;
@@ -202,6 +212,7 @@ struct mptcp_pm_data {
	u8		local_addr_used;
	u8		subflows;
	u8		status;
	DECLARE_BITMAP(id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
	struct mptcp_rm_list rm_list_tx;
	struct mptcp_rm_list rm_list_rx;
};
@@ -241,6 +252,8 @@ struct mptcp_sock {
	u32		token;
	int		rmem_released;
	unsigned long	flags;
	unsigned long	cb_flags;
	unsigned long	push_pending;
	bool		recovery;		/* closing subflow write queue reinjected */
	bool		can_ack;
	bool		fully_established;
@@ -252,7 +265,6 @@ struct mptcp_sock {
	u8		recvmsg_inq:1,
			cork:1,
			nodelay:1;
	spinlock_t	join_list_lock;
	struct work_struct work;
	struct sk_buff  *ooo_last_skb;
	struct rb_root  out_of_order_queue;
@@ -395,6 +407,9 @@ DECLARE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
/* MPTCP subflow context */
struct mptcp_subflow_context {
	struct	list_head node;/* conn_list of subflows */

	char	reset_start[0];

	unsigned long avg_pacing_rate; /* protected by msk socket lock */
	u64	local_key;
	u64	remote_key;
@@ -423,6 +438,7 @@ struct mptcp_subflow_context {
		backup : 1,
		send_mp_prio : 1,
		send_mp_fail : 1,
		send_fastclose : 1,
		rx_eof : 1,
		can_ack : 1,        /* only after processing the remote a key */
		disposable : 1,	    /* ctx can be free at ulp release time */
@@ -441,6 +457,9 @@ struct mptcp_subflow_context {
	u8	stale_count;

	long	delegated_status;

	char	reset_end[0];

	struct	list_head delegated_node;   /* link into delegated_action, protected by local BH */

	u32	setsockopt_seq;
@@ -472,6 +491,13 @@ mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow)
	return subflow->tcp_sock;
}

static inline void
mptcp_subflow_ctx_reset(struct mptcp_subflow_context *subflow)
{
	memset(subflow->reset_start, 0, subflow->reset_end - subflow->reset_start);
	subflow->request_mptcp = 1;
}

static inline u64
mptcp_subflow_get_map_offset(const struct mptcp_subflow_context *subflow)
{
@@ -486,15 +512,6 @@ mptcp_subflow_get_mapped_dsn(const struct mptcp_subflow_context *subflow)
	return subflow->map_seq + mptcp_subflow_get_map_offset(subflow);
}

static inline void mptcp_add_pending_subflow(struct mptcp_sock *msk,
					     struct mptcp_subflow_context *subflow)
{
	sock_hold(mptcp_subflow_tcp_sock(subflow));
	spin_lock_bh(&msk->join_list_lock);
	list_add_tail(&subflow->node, &msk->join_list);
	spin_unlock_bh(&msk->join_list_lock);
}

void mptcp_subflow_process_delegated(struct sock *ssk);

static inline void mptcp_subflow_delegate(struct mptcp_subflow_context *subflow, int action)
@@ -659,7 +676,6 @@ void __mptcp_data_acked(struct sock *sk);
void __mptcp_error_report(struct sock *sk);
void mptcp_subflow_eof(struct sock *sk);
bool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit);
void __mptcp_flush_join_list(struct mptcp_sock *msk);
static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk)
{
	return READ_ONCE(msk->snd_data_fin_enable) &&
@@ -712,6 +728,7 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u8 *msg, int len, void *hmac);

void __init mptcp_pm_init(void);
void mptcp_pm_data_init(struct mptcp_sock *msk);
void mptcp_pm_data_reset(struct mptcp_sock *msk);
void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
void mptcp_pm_nl_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int server_side);
@@ -719,7 +736,9 @@ void mptcp_pm_fully_established(struct mptcp_sock *msk, const struct sock *ssk,
bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk);
void mptcp_pm_connection_closed(struct mptcp_sock *msk);
void mptcp_pm_subflow_established(struct mptcp_sock *msk);
void mptcp_pm_subflow_closed(struct mptcp_sock *msk, u8 id);
bool mptcp_pm_nl_check_work_pending(struct mptcp_sock *msk);
void mptcp_pm_subflow_check_next(struct mptcp_sock *msk, const struct sock *ssk,
				 const struct mptcp_subflow_context *subflow);
void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
				const struct mptcp_addr_info *addr);
void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk,
@@ -816,7 +835,7 @@ unsigned int mptcp_pm_get_subflows_max(struct mptcp_sock *msk);
unsigned int mptcp_pm_get_local_addr_max(struct mptcp_sock *msk);

void mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk);
void mptcp_sockopt_sync_all(struct mptcp_sock *msk);
void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk);

static inline struct mptcp_ext *mptcp_get_ext(const struct sk_buff *skb)
{
Loading