mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge branch 'mptcp-pm-in-kernel-increase-limits'
Matthieu Baerts says: ==================== mptcp: pm: in-kernel: increase limits Allow switching from 8 to 64 for the maximum number of subflows and accepted ADD_ADDR, and from 8 to 255 for the number of MPTCP endpoints. The previous limit of 8 subflows makes sense in most cases. Using more subflows will very likely *not* improve the situation, and could even decrease the performances. But there are no technical limitations nor performance impact to raise this limit, so let's do it: this will allow people with very specific use-cases, and researchers to easily create more subflows, and measure the performance impact by themselves. - Patches 1-2: increase subflows and accepted ADD_ADDR limits. - Patches 3-4: increase endpoints limit. - Patches 5-7: validate the new limits: 64 subflows, 255 endpoints. - Patch 8: selftests: use send()/recv() instead of sendto()/recvfrom(). ==================== Link: https://patch.msgid.link/20260508-net-next-mptcp-pm-inc-limits-v1-0-c84e3fdf9b6a@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
6d596975c1
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -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 *
|
||||
|
|
@ -410,7 +414,8 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
|
|||
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;
|
||||
|
||||
|
|
@ -447,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);
|
||||
|
|
@ -488,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();
|
||||
|
|
@ -559,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);
|
||||
|
|
@ -586,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;
|
||||
}
|
||||
|
||||
|
|
@ -620,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 */
|
||||
|
|
@ -637,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]);
|
||||
|
|
@ -672,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;
|
||||
|
||||
|
|
@ -735,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;
|
||||
}
|
||||
|
|
@ -1212,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_lookup_subflow_by_saddr(&msk->conn_list, &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_remove_anno_list_by_saddr(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);
|
||||
|
|
@ -1235,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,
|
||||
|
|
@ -1254,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);
|
||||
}
|
||||
|
||||
|
|
@ -1371,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;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ unset fastclose
|
|||
unset fullmesh
|
||||
unset speed
|
||||
unset bind_addr
|
||||
unset ifaces_nr
|
||||
unset join_syn_rej
|
||||
unset join_csum_ns1
|
||||
unset join_csum_ns2
|
||||
|
|
@ -146,7 +147,7 @@ init_partial()
|
|||
# ns1eth4 ns2eth4
|
||||
|
||||
local i
|
||||
for i in $(seq 1 4); do
|
||||
for i in $(seq 1 "${ifaces_nr:-4}"); do
|
||||
ip link add ns1eth$i netns "$ns1" type veth peer name ns2eth$i netns "$ns2"
|
||||
ip -net "$ns1" addr add 10.0.$i.1/24 dev ns1eth$i
|
||||
ip -net "$ns1" addr add dead:beef:$i::1/64 dev ns1eth$i nodad
|
||||
|
|
@ -165,7 +166,7 @@ init_partial()
|
|||
init_shapers()
|
||||
{
|
||||
local i
|
||||
for i in $(seq 1 4); do
|
||||
for i in $(seq 1 "${ifaces_nr:-4}"); do
|
||||
tc -n $ns1 qdisc add dev ns1eth$i root netem rate 20mbit delay 1ms
|
||||
tc -n $ns2 qdisc add dev ns2eth$i root netem rate 20mbit delay 1ms
|
||||
done
|
||||
|
|
@ -512,6 +513,19 @@ reset_with_tcp_filter()
|
|||
fi
|
||||
}
|
||||
|
||||
# For kernel supporting limits above 8
|
||||
# $1: title ; $2,4: addrs limit ns1,2 ; $3,5: subflows limit ns1,2
|
||||
reset_with_high_limits()
|
||||
{
|
||||
reset "${1}" || return 1
|
||||
|
||||
if ! pm_nl_set_limits "${ns1}" "${2}" "${3}" 2>/dev/null ||
|
||||
! pm_nl_set_limits "${ns2}" "${4}" "${5}" 2>/dev/null; then
|
||||
mark_as_skipped "unable to set the limits to ${*:2}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# $1: err msg
|
||||
fail_test()
|
||||
{
|
||||
|
|
@ -3669,6 +3683,21 @@ fullmesh_tests()
|
|||
chk_prio_nr 0 1 1 0
|
||||
chk_rm_nr 0 1
|
||||
fi
|
||||
|
||||
# fullmesh in 8x8 to create 63 additional subflows
|
||||
if ifaces_nr=8 reset_with_high_limits "fullmesh 8x8" 64 64 64 64; then
|
||||
# higher chance to lose ADD_ADDR: allow retransmissions
|
||||
ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1
|
||||
local i
|
||||
for i in $(seq 1 8); do
|
||||
pm_nl_add_endpoint $ns2 10.0.$i.2 flags subflow,fullmesh
|
||||
pm_nl_add_endpoint $ns1 10.0.$i.1 flags signal
|
||||
done
|
||||
speed=slow \
|
||||
run_tests $ns1 $ns2 10.0.1.1
|
||||
chk_join_nr 63 63 63
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
fastclose_tests()
|
||||
|
|
|
|||
|
|
@ -66,6 +66,15 @@ get_limits() {
|
|||
fi
|
||||
}
|
||||
|
||||
get_limits_nb() {
|
||||
if mptcp_lib_is_ip_mptcp; then
|
||||
ip -n "${ns1}" mptcp limits | awk '{ print $2" "$4 }'
|
||||
else
|
||||
ip netns exec "${ns1}" ./pm_nl_ctl limits | \
|
||||
awk '{ printf "%s ", $2 }'
|
||||
fi
|
||||
}
|
||||
|
||||
format_endpoints() {
|
||||
mptcp_lib_pm_nl_format_endpoints "${@}"
|
||||
}
|
||||
|
|
@ -164,6 +173,7 @@ check "get_endpoint 2" "" "simple del addr" 1
|
|||
check "show_endpoints" \
|
||||
"$(format_endpoints "1,10.0.1.1" \
|
||||
"3,10.0.1.3,signal backup")" "dump addrs after del"
|
||||
add_endpoint 10.0.1.2 id 2
|
||||
|
||||
add_endpoint 10.0.1.3 2>/dev/null
|
||||
check "get_endpoint 4" "" "duplicate addr" 1
|
||||
|
|
@ -171,25 +181,29 @@ check "get_endpoint 4" "" "duplicate addr" 1
|
|||
add_endpoint 10.0.1.4 flags signal
|
||||
check "get_endpoint 4" "$(format_endpoints "4,10.0.1.4,signal")" "id addr increment"
|
||||
|
||||
for i in $(seq 5 9); do
|
||||
add_endpoint "10.0.1.${i}" flags signal >/dev/null 2>&1
|
||||
done
|
||||
check "get_endpoint 9" "$(format_endpoints "9,10.0.1.9,signal")" "hard addr limit"
|
||||
check "get_endpoint 10" "" "above hard addr limit" 1
|
||||
read -r -a default_limits_nb <<< "$(get_limits_nb)"
|
||||
# limits have been increased: from 8 to 64 for subflows/add_addr & 255 for endp
|
||||
if mptcp_lib_expect_all_features || set_limits 9 9 2>/dev/null; then
|
||||
max_endp=255
|
||||
max_limits=64
|
||||
else
|
||||
max_endp=8
|
||||
max_limits=8
|
||||
fi
|
||||
set_limits "${default_limits_nb[@]}"
|
||||
|
||||
del_endpoint 9
|
||||
for i in $(seq 10 255); do
|
||||
add_endpoint 10.0.0.9 id "${i}"
|
||||
del_endpoint "${i}"
|
||||
for i in $(seq 5 ${max_endp}); do
|
||||
add_endpoint "10.0.0.${i}" id "${i}"
|
||||
done
|
||||
check "show_endpoints" \
|
||||
"$(format_endpoints "1,10.0.1.1" \
|
||||
"3,10.0.1.3,signal backup" \
|
||||
"4,10.0.1.4,signal" \
|
||||
"5,10.0.1.5,signal" \
|
||||
"6,10.0.1.6,signal" \
|
||||
"7,10.0.1.7,signal" \
|
||||
"8,10.0.1.8,signal")" "id limit"
|
||||
check "get_endpoint ${max_endp}" \
|
||||
"$(format_endpoints "${max_endp},10.0.0.${max_endp}")" "id limit"
|
||||
|
||||
if add_endpoint '10.0.0.1' &>/dev/null; then
|
||||
hardlimit="no error"
|
||||
else
|
||||
hardlimit="error"
|
||||
fi
|
||||
check "echo ${hardlimit}" "error" "above hard addr limit"
|
||||
|
||||
flush_endpoint
|
||||
check "show_endpoints" "" "flush addrs"
|
||||
|
|
@ -202,15 +216,15 @@ if ! mptcp_lib_is_ip_mptcp; then
|
|||
flush_endpoint
|
||||
fi
|
||||
|
||||
set_limits 9 1 2>/dev/null
|
||||
set_limits $((max_limits + 1)) 1 2>/dev/null
|
||||
check "get_limits" "${default_limits}" "rcv addrs above hard limit"
|
||||
|
||||
set_limits 1 9 2>/dev/null
|
||||
set_limits 1 $((max_limits + 1)) 2>/dev/null
|
||||
check "get_limits" "${default_limits}" "subflows above hard limit"
|
||||
|
||||
set_limits 8 8
|
||||
set_limits ${max_limits} ${max_limits}
|
||||
flush_endpoint ## to make sure it doesn't affect the limits
|
||||
check "get_limits" "$(format_limits 8 8)" "set limits"
|
||||
check "get_limits" "$(format_limits ${max_limits} ${max_limits})" "set limits"
|
||||
|
||||
flush_endpoint
|
||||
add_endpoint 10.0.1.1
|
||||
|
|
|
|||
|
|
@ -217,8 +217,6 @@ static int capture_events(int fd, int event_group)
|
|||
/* do a netlink command and, if max > 0, fetch the reply ; nh's size >1024B */
|
||||
static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max)
|
||||
{
|
||||
struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
|
||||
socklen_t addr_len;
|
||||
void *data = nh;
|
||||
int rem, ret;
|
||||
int err = 0;
|
||||
|
|
@ -230,15 +228,15 @@ static int do_nl_req(int fd, struct nlmsghdr *nh, int len, int max)
|
|||
}
|
||||
|
||||
nh->nlmsg_len = len;
|
||||
ret = sendto(fd, data, len, 0, (void *)&nladdr, sizeof(nladdr));
|
||||
ret = send(fd, data, len, 0);
|
||||
if (ret != len)
|
||||
error(1, errno, "send netlink: %uB != %uB\n", ret, len);
|
||||
|
||||
addr_len = sizeof(nladdr);
|
||||
rem = ret = recvfrom(fd, data, max, 0, (void *)&nladdr, &addr_len);
|
||||
ret = recv(fd, data, max, 0);
|
||||
if (ret < 0)
|
||||
error(1, errno, "recv netlink: %uB\n", ret);
|
||||
|
||||
rem = ret;
|
||||
/* Beware: the NLMSG_NEXT macro updates the 'rem' argument */
|
||||
for (; NLMSG_OK(nh, rem); nh = NLMSG_NEXT(nh, rem)) {
|
||||
if (nh->nlmsg_type == NLMSG_DONE)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user