summaryrefslogtreecommitdiff
path: root/net/mptcp/pm_kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mptcp/pm_kernel.c')
-rw-r--r--net/mptcp/pm_kernel.c109
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;