// 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. Load more
// 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 bool select_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 bool select_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 int fill_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 int fill_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 int fill_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 int fill_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; }