mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 03:50:24 +09:00
mptcp: pm: in-kernel: usable client side with C-flag
commit 4b1ff850e0c1aacc23e923ed22989b827b9808f9 upstream.
When servers set the C-flag in their MP_CAPABLE to tell clients not to
create subflows to the initial address and port, clients will likely not
use their other endpoints. That's because the in-kernel path-manager
uses the 'subflow' endpoints to create subflows only to the initial
address and port.
If the limits have not been modified to accept ADD_ADDR, the client
doesn't try to establish new subflows. If the limits accept ADD_ADDR,
the routing routes will be used to select the source IP.
The C-flag is typically set when the server is operating behind a legacy
Layer 4 load balancer, or using anycast IP address. Clients having their
different 'subflow' endpoints setup, don't end up creating multiple
subflows as expected, and causing some deployment issues.
A special case is then added here: when servers set the C-flag in the
MPC and directly sends an ADD_ADDR, this single ADD_ADDR is accepted.
The 'subflows' endpoints will then be used with this new remote IP and
port. This exception is only allowed when the ADD_ADDR is sent
immediately after the 3WHS, and makes the client switching to the 'fully
established' mode. After that, 'select_local_address()' will not be able
to find any subflows, because 'id_avail_bitmap' will be filled in
mptcp_pm_create_subflow_or_signal_addr(), when switching to 'fully
established' mode.
Fixes: df377be387 ("mptcp: add deny_join_id0 in mptcp_options_received")
Cc: stable@vger.kernel.org
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/536
Reviewed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20250925-net-next-mptcp-c-flag-laminar-v1-1-ad126cc47c6b@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ Conflict in pm.c, because commit 498d7d8b75f1 ("mptcp: pm: remove
'_nl' from mptcp_pm_nl_is_init_remote_addr") renamed an helper in the
context, and it is not in this version. The same new code can be
applied at the same place.
Conflict in pm_kernel.c, because the modified code has been moved from
pm_netlink.c to pm_kernel.c in commit 8617e85e04bd ("mptcp: pm: split
in-kernel PM specific code"), which is not in this version. The
resolution is easy: simply by applying the patch where 'pm_kernel.c'
has been replaced 'pm_netlink.c'.
Conflict in pm_netlink.c, because commit b83fbca1b4c9 ("mptcp: pm:
reduce entries iterations on connect") is not in this version. Instead
of using the 'locals' variable (struct mptcp_pm_local *) from the new
version and embedding a "struct mptcp_addr_info", we can simply
continue to use the 'addrs' variable (struct mptcp_addr_info *).
Conflict in protocol.h, because commit af3dc0ad3167 ("mptcp: Remove
unused declaration mptcp_sockopt_sync()") is not in this version and
it removed one line in the context. The resolution is easy because the
new function can still be added at the same place. ]
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
06d82c3a1f
commit
63c44fa29e
@@ -227,9 +227,12 @@ void mptcp_pm_add_addr_received(const struct sock *ssk,
|
||||
} else {
|
||||
__MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_ADDADDRDROP);
|
||||
}
|
||||
/* id0 should not have a different address */
|
||||
/* - id0 should not have a different address
|
||||
* - special case for C-flag: linked to fill_local_addresses_vec()
|
||||
*/
|
||||
} else if ((addr->id == 0 && !mptcp_pm_nl_is_init_remote_addr(msk, addr)) ||
|
||||
(addr->id > 0 && !READ_ONCE(pm->accept_addr))) {
|
||||
(addr->id > 0 && !READ_ONCE(pm->accept_addr) &&
|
||||
!mptcp_pm_add_addr_c_flag_case(msk))) {
|
||||
mptcp_pm_announce_addr(msk, addr, true);
|
||||
mptcp_pm_add_addr_send_ack(msk);
|
||||
} else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) {
|
||||
|
||||
@@ -675,10 +675,12 @@ static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk,
|
||||
struct mptcp_addr_info mpc_addr;
|
||||
struct pm_nl_pernet *pernet;
|
||||
unsigned int subflows_max;
|
||||
bool c_flag_case;
|
||||
int i = 0;
|
||||
|
||||
pernet = pm_nl_get_pernet_from_msk(msk);
|
||||
subflows_max = mptcp_pm_get_subflows_max(msk);
|
||||
c_flag_case = remote->id && mptcp_pm_add_addr_c_flag_case(msk);
|
||||
|
||||
mptcp_local_address((struct sock_common *)msk, &mpc_addr);
|
||||
|
||||
@@ -691,11 +693,26 @@ static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk,
|
||||
continue;
|
||||
|
||||
if (msk->pm.subflows < subflows_max) {
|
||||
bool is_id0;
|
||||
|
||||
msk->pm.subflows++;
|
||||
addrs[i] = entry->addr;
|
||||
|
||||
is_id0 = mptcp_addresses_equal(&entry->addr,
|
||||
&mpc_addr,
|
||||
entry->addr.port);
|
||||
|
||||
if (c_flag_case &&
|
||||
(entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)) {
|
||||
__clear_bit(addrs[i].id,
|
||||
msk->pm.id_avail_bitmap);
|
||||
|
||||
if (!is_id0)
|
||||
msk->pm.local_addr_used++;
|
||||
}
|
||||
|
||||
/* Special case for ID0: set the correct ID */
|
||||
if (mptcp_addresses_equal(&entry->addr, &mpc_addr, entry->addr.port))
|
||||
if (is_id0)
|
||||
addrs[i].id = 0;
|
||||
|
||||
i++;
|
||||
@@ -703,6 +720,39 @@ static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk,
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Special case: peer sets the C flag, accept one ADD_ADDR if default
|
||||
* limits are used -- accepting no ADD_ADDR -- and use subflow endpoints
|
||||
*/
|
||||
if (!i && c_flag_case) {
|
||||
unsigned int local_addr_max = mptcp_pm_get_local_addr_max(msk);
|
||||
|
||||
while (msk->pm.local_addr_used < local_addr_max &&
|
||||
msk->pm.subflows < subflows_max) {
|
||||
struct mptcp_pm_addr_entry local;
|
||||
|
||||
if (!select_local_address(pernet, msk, &local))
|
||||
break;
|
||||
|
||||
__clear_bit(local.addr.id, msk->pm.id_avail_bitmap);
|
||||
|
||||
if (!mptcp_pm_addr_families_match(sk, &local.addr,
|
||||
remote))
|
||||
continue;
|
||||
|
||||
if (mptcp_addresses_equal(&local.addr, &mpc_addr,
|
||||
local.addr.port))
|
||||
continue;
|
||||
|
||||
addrs[i] = local.addr;
|
||||
|
||||
msk->pm.local_addr_used++;
|
||||
msk->pm.subflows++;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* If the array is empty, fill in the single
|
||||
* 'IPADDRANY' local address
|
||||
*/
|
||||
|
||||
@@ -1080,6 +1080,14 @@ static inline void mptcp_pm_close_subflow(struct mptcp_sock *msk)
|
||||
spin_unlock_bh(&msk->pm.lock);
|
||||
}
|
||||
|
||||
static inline bool mptcp_pm_add_addr_c_flag_case(struct mptcp_sock *msk)
|
||||
{
|
||||
return READ_ONCE(msk->pm.remote_deny_join_id0) &&
|
||||
msk->pm.local_addr_used == 0 &&
|
||||
mptcp_pm_get_add_addr_accept_max(msk) == 0 &&
|
||||
msk->pm.subflows < mptcp_pm_get_subflows_max(msk);
|
||||
}
|
||||
|
||||
void mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk);
|
||||
void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user