diff options
Diffstat (limited to 'net/mptcp/pm_kernel.c')
| -rw-r--r-- | net/mptcp/pm_kernel.c | 109 |
1 files changed, 70 insertions, 39 deletions
diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c index 0ebf43be9939..424f1a7f9248 100644 --- a/net/mptcp/pm_kernel.c +++ b/net/mptcp/pm_kernel.c @@ -30,6 +30,7 @@ struct pm_nl_pernet { }; #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) { @@ -95,13 +96,13 @@ 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)) & @@ -201,7 +202,8 @@ fill_remote_addr(struct mptcp_sock *msk, struct mptcp_addr_info *local, static unsigned int fill_remote_addresses_fullmesh(struct mptcp_sock *msk, struct mptcp_addr_info *local, - struct mptcp_addr_info *addrs) + 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); @@ -236,7 +238,8 @@ fill_remote_addresses_fullmesh(struct mptcp_sock *msk, msk->pm.extra_subflows++; i++; - if (msk->pm.extra_subflows >= limit_extra_subflows) + if (msk->pm.extra_subflows >= limit_extra_subflows || + i == addrs_size) break; } @@ -248,7 +251,8 @@ fill_remote_addresses_fullmesh(struct mptcp_sock *msk, */ static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk, struct mptcp_addr_info *local, - bool fullmesh, struct mptcp_addr_info *addrs) + 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. @@ -257,7 +261,7 @@ fill_remote_addresses_vec(struct mptcp_sock *msk, struct mptcp_addr_info *local, return fill_remote_addr(msk, local, addrs); /* Fullmesh endpoint: fill all possible remote addresses */ - return fill_remote_addresses_fullmesh(msk, local, addrs); + return fill_remote_addresses_fullmesh(msk, local, addrs, addrs_size); } static struct mptcp_pm_addr_entry * @@ -347,6 +351,8 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) /* 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 @@ -360,19 +366,20 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) 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_alloc_anno_list(msk, &local.addr)) + if (!mptcp_pm_announced_alloc(msk, &local.addr)) return; - __clear_bit(local.addr.id, msk->pm.id_avail_bitmap); + __clear_bit(endp_id, msk->pm.id_avail_bitmap); msk->pm.add_addr_signaled++; - /* Special case for ID0: set the correct ID */ - if (local.addr.id == msk->mpc_endpoint_id) - local.addr.id = 0; - mptcp_pm_announce_addr(msk, &local.addr, false); mptcp_pm_addr_send_ack(msk); @@ -407,7 +414,8 @@ subflow: 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); + nr = fill_remote_addresses_vec(msk, &local.addr, fullmesh, + addrs, ARRAY_SIZE(addrs)); if (nr == 0) continue; @@ -444,6 +452,7 @@ 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); @@ -485,7 +494,8 @@ fill_local_addresses_vec_fullmesh(struct mptcp_sock *msk, msk->pm.extra_subflows++; i++; - if (msk->pm.extra_subflows >= limit_extra_subflows) + if (msk->pm.extra_subflows >= limit_extra_subflows || + i == locals_size) break; } rcu_read_unlock(); @@ -556,7 +566,8 @@ fill_local_laminar_endp(struct mptcp_sock *msk, struct mptcp_addr_info *remote, static unsigned int fill_local_addresses_vec_c_flag(struct mptcp_sock *msk, struct mptcp_addr_info *remote, - struct mptcp_pm_local *locals) + struct mptcp_pm_local *locals, + int locals_size) { u8 limit_extra_subflows = mptcp_pm_get_limit_extra_subflows(msk); struct pm_nl_pernet *pernet = pm_nl_get_pernet_from_msk(msk); @@ -583,7 +594,8 @@ fill_local_addresses_vec_c_flag(struct mptcp_sock *msk, msk->pm.extra_subflows++; i++; - if (msk->pm.extra_subflows >= limit_extra_subflows) + if (msk->pm.extra_subflows >= limit_extra_subflows || + i == locals_size) break; } @@ -617,13 +629,14 @@ fill_local_address_any(struct mptcp_sock *msk, struct mptcp_addr_info *remote, */ static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk, struct mptcp_addr_info *remote, - struct mptcp_pm_local *locals) + struct mptcp_pm_local *locals, int locals_size) { bool c_flag_case = remote->id && mptcp_pm_add_addr_c_flag_case(msk); /* If there is at least one MPTCP endpoint with a fullmesh flag */ if (mptcp_pm_get_endp_fullmesh_max(msk)) return fill_local_addresses_vec_fullmesh(msk, remote, locals, + locals_size, c_flag_case); /* If there is at least one MPTCP endpoint with a laminar flag */ @@ -634,7 +647,8 @@ fill_local_addresses_vec(struct mptcp_sock *msk, struct mptcp_addr_info *remote, * limits are used -- accepting no ADD_ADDR -- and use subflow endpoints */ if (c_flag_case) - return fill_local_addresses_vec_c_flag(msk, remote, locals); + return fill_local_addresses_vec_c_flag(msk, remote, locals, + locals_size); /* No special case: fill in the single 'IPADDRANY' local address */ return fill_local_address_any(msk, remote, &locals[0]); @@ -659,7 +673,7 @@ 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 */ @@ -669,7 +683,7 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk) /* connect to the specified remote address, using whatever * local address the routing configuration will pick. */ - nr = fill_local_addresses_vec(msk, &remote, locals); + nr = fill_local_addresses_vec(msk, &remote, locals, ARRAY_SIZE(locals)); if (nr == 0) return; @@ -732,7 +746,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet, */ if (pernet->next_id == MPTCP_PM_MAX_ADDR_ID) pernet->next_id = 1; - if (pernet->endpoints >= MPTCP_PM_ADDR_MAX) { + if (pernet->endpoints == MPTCP_PM_MAX_ADDR_ID) { ret = -ERANGE; goto out; } @@ -1039,7 +1053,7 @@ out_free: 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) { @@ -1048,7 +1062,7 @@ 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) @@ -1084,8 +1098,8 @@ 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); - mptcp_pm_remove_anno_addr(msk, addr, remove_subflow && + remove_subflow = mptcp_pm_has_subflow_saddr(msk, addr); + 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); @@ -1209,19 +1223,30 @@ int mptcp_pm_nl_del_addr_doit(struct sk_buff *skb, struct genl_info *info) } static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk, - struct list_head *rm_list) + struct list_head *rm_list, + struct mptcp_pm_addr_entry *entry) { - struct mptcp_rm_list alist = { .nr = 0 }, slist = { .nr = 0 }; - struct mptcp_pm_addr_entry *entry; + struct mptcp_rm_list alist, slist; + bool more; - list_for_each_entry(entry, rm_list, list) { - if (slist.nr < MPTCP_RM_IDS_MAX && - mptcp_lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) +again: + alist.nr = 0; + slist.nr = 0; + more = false; + + entry = list_prepare_entry(entry, rm_list, list); + list_for_each_entry_continue(entry, rm_list, list) { + if (mptcp_pm_has_subflow_saddr(msk, &entry->addr)) slist.ids[slist.nr++] = mptcp_endp_get_local_id(msk, &entry->addr); - if (alist.nr < MPTCP_RM_IDS_MAX && - 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 || + alist.nr == MPTCP_RM_IDS_MAX) { + more = !list_is_last(&entry->list, rm_list); + break; + } } spin_lock_bh(&msk->pm.lock); @@ -1232,9 +1257,14 @@ static void mptcp_pm_flush_addrs_and_subflows(struct mptcp_sock *msk, if (slist.nr) mptcp_pm_rm_subflow(msk, &slist); /* Reset counters: maybe some subflows have been removed before */ - bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); - msk->pm.local_addr_used = 0; + if (!more) { + bitmap_fill(msk->pm.id_avail_bitmap, MPTCP_PM_MAX_ADDR_ID + 1); + msk->pm.local_addr_used = 0; + } spin_unlock_bh(&msk->pm.lock); + + if (more) + goto again; } static void mptcp_nl_flush_addrs_list(struct net *net, @@ -1251,7 +1281,7 @@ static void mptcp_nl_flush_addrs_list(struct net *net, if (!mptcp_pm_is_userspace(msk)) { lock_sock(sk); - mptcp_pm_flush_addrs_and_subflows(msk, rm_list); + mptcp_pm_flush_addrs_and_subflows(msk, rm_list, NULL); release_sock(sk); } @@ -1278,6 +1308,7 @@ static void __reset_counters(struct pm_nl_pernet *pernet) WRITE_ONCE(pernet->endp_signal_max, 0); WRITE_ONCE(pernet->endp_subflow_max, 0); WRITE_ONCE(pernet->endp_laminar_max, 0); + WRITE_ONCE(pernet->endp_fullmesh_max, 0); pernet->endpoints = 0; } @@ -1367,10 +1398,10 @@ static int parse_limit(struct genl_info *info, int id, unsigned int *limit) return 0; *limit = nla_get_u32(attr); - if (*limit > MPTCP_PM_ADDR_MAX) { + if (*limit > MPTCP_PM_SUBFLOWS_MAX) { NL_SET_ERR_MSG_ATTR_FMT(info->extack, attr, "limit greater than maximum (%u)", - MPTCP_PM_ADDR_MAX); + MPTCP_PM_SUBFLOWS_MAX); return -EINVAL; } return 0; |
