1663 lines · 43.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* Multipath TCP * * Copyright (c) 2025, Matthieu Baerts. */ #define pr_fmt(fmt) "MPTCP: " fmt #include <net/netns/generic.h> #include "protocol.h"#include "mib.h"#include "mptcp_pm_gen.h" static int pm_nl_pernet_id; struct pm_nl_pernet {	/* protects pernet updates */	spinlock_t		lock;	struct list_head	endp_list;	u8			endpoints;	u8			endp_signal_max;	u8			endp_subflow_max;	u8			endp_laminar_max;	u8			endp_fullmesh_max;	u8			limit_add_addr_accepted;	u8			limit_extra_subflows;	u8			next_id;	DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);}; #define MPTCP_PM_ADDR_MAX	8#define MPTCP_PM_SUBFLOWS_MAX	64 static struct pm_nl_pernet *pm_nl_get_pernet(const struct net *net){	return net_generic(net, pm_nl_pernet_id);} static struct pm_nl_pernet *pm_nl_get_pernet_from_msk(const struct mptcp_sock *msk){	return pm_nl_get_pernet(sock_net((struct sock *)msk));} static struct pm_nl_pernet *genl_info_pm_nl(struct genl_info *info){	return pm_nl_get_pernet(genl_info_net(info));} u8 mptcp_pm_get_endp_signal_max(const struct mptcp_sock *msk){	const struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 	return READ_ONCE(pernet->endp_signal_max);}EXPORT_SYMBOL_GPL(mptcp_pm_get_endp_signal_max); u8 mptcp_pm_get_endp_subflow_max(const struct mptcp_sock *msk){	struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 	return READ_ONCE(pernet->endp_subflow_max);}EXPORT_SYMBOL_GPL(mptcp_pm_get_endp_subflow_max); u8 mptcp_pm_get_endp_laminar_max(const struct mptcp_sock *msk){	struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 	return READ_ONCE(pernet->endp_laminar_max);}EXPORT_SYMBOL_GPL(mptcp_pm_get_endp_laminar_max); u8 mptcp_pm_get_endp_fullmesh_max(const struct mptcp_sock *msk){	struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 	return READ_ONCE(pernet->endp_fullmesh_max);}EXPORT_SYMBOL_GPL(mptcp_pm_get_endp_fullmesh_max); u8 mptcp_pm_get_limit_add_addr_accepted(const struct mptcp_sock *msk){	struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 	return READ_ONCE(pernet->limit_add_addr_accepted);}EXPORT_SYMBOL_GPL(mptcp_pm_get_limit_add_addr_accepted); u8 mptcp_pm_get_limit_extra_subflows(const struct mptcp_sock *msk){	struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); 	return READ_ONCE(pernet->limit_extra_subflows);}EXPORT_SYMBOL_GPL(mptcp_pm_get_limit_extra_subflows); 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; 	mptcp_for_each_subflow(msk, subflow) {		struct sock *ssk = mptcp_subflow_tcp_sock(subflow); 		if (!((1 << inet_sk_state_load(ssk)) &		      (TCPF_ESTABLISHED | TCPF_SYN_SENT | TCPF_SYN_RECV)))			continue; 		mptcp_remote_address((struct sock_common *)ssk, &cur);		if (mptcp_addresses_equal(&cur, daddr, daddr->port))			return true;	} 	return false;} static boolselect_local_address(const struct pm_nl_pernet *pernet,		     const struct mptcp_sock *msk,		     struct mptcp_pm_local *new_local){	struct mptcp_pm_addr_entry *entry;	bool found = false; 	msk_owned_by_me(msk); 	rcu_read_lock();	list_for_each_entry_rcu(entry, &pernet->endp_list, list) {		if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW))			continue; 		if (!test_bit(entry->addr.id, msk->pm.id_avail_bitmap))			continue; 		new_local->addr = entry->addr;		new_local->flags = entry->flags;		new_local->ifindex = entry->ifindex;		found = true;		break;	}	rcu_read_unlock(); 	return found;} static boolselect_signal_address(struct pm_nl_pernet *pernet, const struct mptcp_sock *msk,		      struct mptcp_pm_local *new_local){	struct mptcp_pm_addr_entry *entry;	bool found = false; 	rcu_read_lock();	/* do not keep any additional per socket state, just signal	 * the address list in order.	 * Note: removal from the local address list during the msk life-cycle	 * can lead to additional addresses not being announced.	 */	list_for_each_entry_rcu(entry, &pernet->endp_list, list) {		if (!test_bit(entry->addr.id, msk->pm.id_avail_bitmap))			continue; 		if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL))			continue; 		new_local->addr = entry->addr;		new_local->flags = entry->flags;		new_local->ifindex = entry->ifindex;		found = true;		break;	}	rcu_read_unlock(); 	return found;} static unsigned intfill_remote_addr(struct mptcp_sock *msk, struct mptcp_addr_info *local,		 struct mptcp_addr_info *addrs){	bool deny_id0 = READ_ONCE(msk->pm.remote_deny_join_id0);	struct mptcp_addr_info remote = { 0 };	struct sock *sk = (struct sock *)msk; 	if (deny_id0)		return 0; 	mptcp_remote_address((struct sock_common *)sk, &remote); 	if (!mptcp_pm_addr_families_match(sk, local, &remote))		return 0; 	msk->pm.extra_subflows++;	*addrs = remote; 	return 1;} static unsigned intfill_remote_addresses_fullmesh(struct mptcp_sock *msk,			       struct mptcp_addr_info *local,			       struct mptcp_addr_info *addrs,			       int addrs_size){	u8 limit_extra_subflows = mptcp_pm_get_limit_extra_subflows(msk);	bool deny_id0 = READ_ONCE(msk->pm.remote_deny_join_id0);	DECLARE_BITMAP(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1);	struct sock *sk = (struct sock *)msk, *ssk;	struct mptcp_subflow_context *subflow;	int i = 0; 	/* Forbid creation of new subflows matching existing ones, possibly	 * already created by incoming ADD_ADDR	 */	bitmap_zero(unavail_id, MPTCP_PM_MAX_ADDR_ID + 1);	mptcp_for_each_subflow(msk, subflow)		if (READ_ONCE(subflow->local_id) == local->id)			__set_bit(subflow->remote_id, unavail_id); 	mptcp_for_each_subflow(msk, subflow) {		ssk = mptcp_subflow_tcp_sock(subflow);		mptcp_remote_address((struct sock_common *)ssk, &addrs[i]);		addrs[i].id = READ_ONCE(subflow->remote_id);		if (deny_id0 && !addrs[i].id)			continue; 		if (test_bit(addrs[i].id, unavail_id))			continue; 		if (!mptcp_pm_addr_families_match(sk, local, &addrs[i]))			continue; 		/* forbid creating multiple address towards this id */		__set_bit(addrs[i].id, unavail_id);		msk->pm.extra_subflows++;		i++; 		if (msk->pm.extra_subflows >= limit_extra_subflows ||		    i == addrs_size)			break;	} 	return i;} /* Fill all the remote addresses into the array addrs[], * and return the array size. */static unsigned intfill_remote_addresses_vec(struct mptcp_sock *msk, struct mptcp_addr_info *local,			  bool fullmesh, struct mptcp_addr_info *addrs,			  int addrs_size){	/* Non-fullmesh: fill in the single entry corresponding to the primary	 * MPC subflow remote address, and return 1, corresponding to 1 entry.	 */	if (!fullmesh)		return fill_remote_addr(msk, local, addrs); 	/* Fullmesh endpoint: fill all possible remote addresses */	return fill_remote_addresses_fullmesh(msk, local, addrs, addrs_size);} 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_rcu(entry, &pernet->endp_list, list,				lockdep_is_held(&pernet->lock)) {		if (entry->addr.id == id)			return entry;	}	return NULL;} static struct mptcp_pm_addr_entry *__lookup_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *info){	struct mptcp_pm_addr_entry *entry; 	list_for_each_entry_rcu(entry, &pernet->endp_list, list,				lockdep_is_held(&pernet->lock)) {		if (mptcp_addresses_equal(&entry->addr, info, entry->addr.port))			return entry;	}	return NULL;} static u8 mptcp_endp_get_local_id(struct mptcp_sock *msk,				  const struct mptcp_addr_info *addr){	return msk->mpc_endpoint_id == addr->id ? 0 : addr->id;} /* Set mpc_endpoint_id, and send MP_PRIO for ID0 if needed */static void mptcp_mpc_endpoint_setup(struct mptcp_sock *msk){	struct mptcp_subflow_context *subflow;	struct mptcp_pm_addr_entry *entry;	struct mptcp_addr_info mpc_addr;	struct pm_nl_pernet *pernet;	bool backup = false; 	/* do lazy endpoint usage accounting for the MPC subflows */	if (likely(msk->pm.status & BIT(MPTCP_PM_MPC_ENDPOINT_ACCOUNTED)) ||	    !msk->first)		return; 	subflow = mptcp_subflow_ctx(msk->first);	pernet = pm_nl_get_pernet_from_msk(msk); 	mptcp_local_address((struct sock_common *)msk->first, &mpc_addr);	rcu_read_lock();	entry = __lookup_addr(pernet, &mpc_addr);	if (entry) {		__clear_bit(entry->addr.id, msk->pm.id_avail_bitmap);		msk->mpc_endpoint_id = entry->addr.id;		backup = !!(entry->flags & MPTCP_PM_ADDR_FLAG_BACKUP);	}	rcu_read_unlock(); 	/* Send MP_PRIO */	if (backup)		mptcp_pm_send_ack(msk, subflow, true, backup); 	msk->pm.status |= BIT(MPTCP_PM_MPC_ENDPOINT_ACCOUNTED);} static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk){	u8 limit_extra_subflows = mptcp_pm_get_limit_extra_subflows(msk);	struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk);	u8 endp_subflow_max = mptcp_pm_get_endp_subflow_max(msk);	u8 endp_signal_max = mptcp_pm_get_endp_signal_max(msk);	struct sock *sk = (struct sock *)msk;	bool signal_and_subflow = false;	struct mptcp_pm_local local; 	mptcp_mpc_endpoint_setup(msk);	if (!mptcp_is_fully_established(sk))		return; 	pr_debug("local %d:%d signal %d:%d subflows %d:%d\n",		 msk->pm.local_addr_used, endp_subflow_max,		 msk->pm.add_addr_signaled, endp_signal_max,		 msk->pm.extra_subflows, limit_extra_subflows); 	/* check first for announce */	if (msk->pm.add_addr_signaled < endp_signal_max) {		u8 endp_id; 		/* due to racing events on both ends we can reach here while		 * previous add address is still running: if we invoke now		 * mptcp_pm_announce_addr(), that will fail and the		 * corresponding id will be marked as used.		 * Instead let the PM machinery reschedule us when the		 * current address announce will be completed.		 */		if (msk->pm.addr_signal & BIT(MPTCP_ADD_ADDR_SIGNAL))			return; 		if (!select_signal_address(pernet, msk, &local))			goto subflow; 		/* Special case for ID0: set the correct ID */		endp_id = local.addr.id;		if (endp_id == msk->mpc_endpoint_id)			local.addr.id = 0; 		/* If the alloc fails, we are on memory pressure, not worth		 * continuing, and trying to create subflows.		 */		if (!mptcp_pm_announced_alloc(msk, &local.addr))			return; 		__clear_bit(endp_id, msk->pm.id_avail_bitmap);		msk->pm.add_addr_signaled++; 		mptcp_pm_announce_addr(msk, &local.addr, false);		mptcp_pm_addr_send_ack(msk); 		if (local.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)			signal_and_subflow = true;	} subflow:	/* No need to try establishing subflows to remote id0 if not allowed */	if (mptcp_pm_add_addr_c_flag_case(msk))		goto exit; 	/* check if should create a new subflow */	while (msk->pm.local_addr_used < endp_subflow_max &&	       msk->pm.extra_subflows < limit_extra_subflows) {		struct mptcp_addr_info addrs[MPTCP_PM_ADDR_MAX];		bool fullmesh;		int i, nr; 		if (signal_and_subflow)			signal_and_subflow = false;		else if (!select_local_address(pernet, msk, &local))			break; 		fullmesh = !!(local.flags & MPTCP_PM_ADDR_FLAG_FULLMESH); 		__clear_bit(local.addr.id, msk->pm.id_avail_bitmap); 		/* Special case for ID0: set the correct ID */		if (local.addr.id == msk->mpc_endpoint_id)			local.addr.id = 0;		else /* local_addr_used is not decr for ID 0 */			msk->pm.local_addr_used++; 		nr = fill_remote_addresses_vec(msk, &local.addr, fullmesh,					       addrs, ARRAY_SIZE(addrs));		if (nr == 0)			continue; 		spin_unlock_bh(&msk->pm.lock);		for (i = 0; i < nr; i++)			__mptcp_subflow_connect(sk, &local, &addrs[i]);		spin_lock_bh(&msk->pm.lock);	} exit:	/* If an endpoint has both the signal and subflow flags, but it is not	 * possible to create subflows -- the 'while' loop body above never	 * executed --  then still mark the endp as used, which is somehow the	 * case. This avoids issues later when removing the endpoint and calling	 * __mark_subflow_endp_available(), which expects the increment here.	 */	if (signal_and_subflow && local.addr.id != msk->mpc_endpoint_id)		msk->pm.local_addr_used++; 	mptcp_pm_nl_check_work_pending(msk);} static void mptcp_pm_nl_fully_established(struct mptcp_sock *msk){	mptcp_pm_create_subflow_or_signal_addr(msk);} static void mptcp_pm_nl_subflow_established(struct mptcp_sock *msk){	mptcp_pm_create_subflow_or_signal_addr(msk);} static unsigned intfill_local_addresses_vec_fullmesh(struct mptcp_sock *msk,				  struct mptcp_addr_info *remote,				  struct mptcp_pm_local *locals,				  int locals_size,				  bool c_flag_case){	u8 limit_extra_subflows = mptcp_pm_get_limit_extra_subflows(msk);	struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk);	struct sock *sk = (struct sock *)msk;	struct mptcp_pm_addr_entry *entry;	struct mptcp_pm_local *local;	int i = 0; 	rcu_read_lock();	list_for_each_entry_rcu(entry, &pernet->endp_list, list) {		bool is_id0; 		if (!(entry->flags & MPTCP_PM_ADDR_FLAG_FULLMESH))			continue; 		if (!mptcp_pm_addr_families_match(sk, &entry->addr, remote))			continue; 		local = &locals[i];		local->addr = entry->addr;		local->flags = entry->flags;		local->ifindex = entry->ifindex; 		is_id0 = local->addr.id == msk->mpc_endpoint_id; 		if (c_flag_case &&		    (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)) {			__clear_bit(local->addr.id, msk->pm.id_avail_bitmap); 			if (!is_id0)				msk->pm.local_addr_used++;		} 		/* Special case for ID0: set the correct ID */		if (is_id0)			local->addr.id = 0; 		msk->pm.extra_subflows++;		i++; 		if (msk->pm.extra_subflows >= limit_extra_subflows ||		    i == locals_size)			break;	}

Lines 1–500 of 1663.