From 7eafe678d45fa1dbbd6ab2ba5676a806aaae4591 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Thu, 9 Oct 2025 17:32:10 +0200 Subject: [PATCH 1/4] include: update MPTCP upstream headers Some new defines related to MPTCP_INFO and EV flags, and switch to _BITUL(). Signed-off-by: Matthieu Baerts (NGI0) --- include/linux/mptcp_upstream.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/include/linux/mptcp_upstream.h b/include/linux/mptcp_upstream.h index 5c584174..a0fc1015 100644 --- a/include/linux/mptcp_upstream.h +++ b/include/linux/mptcp_upstream.h @@ -34,19 +34,24 @@ #define MPTCP_PM_EV_FLAG_DENY_JOIN_ID0 _BITUL(0) #define MPTCP_PM_EV_FLAG_SERVER_SIDE _BITUL(1) -#define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0) -#define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1) -#define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) -#define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3) -#define MPTCP_PM_ADDR_FLAG_IMPLICIT (1 << 4) +#define MPTCP_PM_ADDR_FLAG_SIGNAL _BITUL(0) +#define MPTCP_PM_ADDR_FLAG_SUBFLOW _BITUL(1) +#define MPTCP_PM_ADDR_FLAG_BACKUP _BITUL(2) +#define MPTCP_PM_ADDR_FLAG_FULLMESH _BITUL(3) +#define MPTCP_PM_ADDR_FLAG_IMPLICIT _BITUL(4) struct mptcp_info { __u8 mptcpi_subflows; + #define mptcpi_extra_subflows mptcpi_subflows __u8 mptcpi_add_addr_signal; __u8 mptcpi_add_addr_accepted; __u8 mptcpi_subflows_max; + #define mptcpi_limit_extra_subflows mptcpi_subflows_max __u8 mptcpi_add_addr_signal_max; + #define mptcpi_endp_signal_max mptcpi_add_addr_signal_max __u8 mptcpi_add_addr_accepted_max; + #define mptcpi_limit_add_addr_accepted mptcpi_add_addr_accepted_max + /* 16-bit hole that can no longer be filled */ __u32 mptcpi_flags; __u32 mptcpi_token; __u64 mptcpi_write_seq; @@ -54,7 +59,9 @@ struct mptcp_info { __u64 mptcpi_rcv_nxt; __u8 mptcpi_local_addr_used; __u8 mptcpi_local_addr_max; + #define mptcpi_endp_subflow_max mptcpi_local_addr_max __u8 mptcpi_csum_enabled; + /* 8-bit hole that can no longer be filled */ __u32 mptcpi_retransmits; __u64 mptcpi_bytes_retrans; __u64 mptcpi_bytes_sent; From 4ac0850fc1fc24052833fb928d004e89abaaca0b Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Thu, 9 Oct 2025 18:02:57 +0200 Subject: [PATCH 2/4] flags: add 'luminar' endpoints support Currently, upon the reception of an ADD_ADDR (and when the fullmesh flag is not used), the in-kernel PM will create new subflows using the local address the routing configuration will pick. It would be easier to pick local addresses from a selected list of endpoints, and use it only once, than relying on routing rules. Use case: both the client (C) and the server (S) have two addresses (a and b). The client establishes the connection between C(a) and S(a). Once established, the server announces its additional address S(b). Once received, the client connects to it using its second address C(b). Compared to a situation without the 'laminar' endpoint for C(b), the client didn't use this address C(b) to establish a subflow to the server's primary address S(a). So at the end, we have: C S C(a) --- S(a) C(b) --- S(b) In case of a 3rd address on each side (C(c) and S(c)), upon the reception of an ADD_ADDR with S(c), the client should not pick C(b) because it has already been used. C(c) should then be used. Note that this situation is currently possible if C doesn't add any endpoint, but configure the routing in order to pick C(b) for the route to S(b), and pick C(c) for the route to S(c). That doesn't sound very practical because it means knowing in advance the IP addresses that will be used and announced by the server. 'laminar', like the idea of laminar flows: the different subflows don't mix with each other on an endpoint, unlike the "turbulent" way traffic is mixed by 'fullmesh'. This new flag is then added to mptcpd as well. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/503 Link: https://git.kernel.org/netdev/net-next/c/539f6b9de39e Signed-off-by: Matthieu Baerts (NGI0) --- etc/mptcpd.conf.in | 1 + include/linux/mptcp_upstream.h | 4 +++- include/mptcpd/types.h | 3 +++ man/mptcpd.8.in | 3 ++- plugins/path_managers/addr_adv.c | 3 ++- src/configuration.c | 1 + src/netlink_pm_upstream.c | 3 ++- 7 files changed, 14 insertions(+), 4 deletions(-) diff --git a/etc/mptcpd.conf.in b/etc/mptcpd.conf.in index e33ab4f9..19b2cdc8 100644 --- a/etc/mptcpd.conf.in +++ b/etc/mptcpd.conf.in @@ -37,6 +37,7 @@ path-manager=@mptcpd_default_pm@ # signal (do not use with the "fullmesh" flag) # backup # fullmesh (do not use with the "signal" flag) +# laminar # # Plugins that deal with the in-kernel path manager may use these # flags when advertising addresses. diff --git a/include/linux/mptcp_upstream.h b/include/linux/mptcp_upstream.h index a0fc1015..a13655ca 100644 --- a/include/linux/mptcp_upstream.h +++ b/include/linux/mptcp_upstream.h @@ -39,6 +39,7 @@ #define MPTCP_PM_ADDR_FLAG_BACKUP _BITUL(2) #define MPTCP_PM_ADDR_FLAG_FULLMESH _BITUL(3) #define MPTCP_PM_ADDR_FLAG_IMPLICIT _BITUL(4) +#define MPTCP_PM_ADDR_FLAG_LAMINAR _BITUL(5) struct mptcp_info { __u8 mptcpi_subflows; @@ -68,7 +69,8 @@ struct mptcp_info { __u64 mptcpi_bytes_received; __u64 mptcpi_bytes_acked; __u8 mptcpi_subflows_total; - __u8 reserved[3]; + __u8 mptcpi_endp_laminar_max; + __u8 reserved[2]; __u32 mptcpi_last_data_sent; __u32 mptcpi_last_data_recv; __u32 mptcpi_last_ack_recv; diff --git a/include/mptcpd/types.h b/include/mptcpd/types.h index ed16a810..56bba74d 100644 --- a/include/mptcpd/types.h +++ b/include/mptcpd/types.h @@ -73,6 +73,9 @@ typedef uint32_t mptcpd_flags_t; * @note Do not use with @c MPTCPD_ADDR_FLAG_SIGNAL. */ #define MPTCPD_ADDR_FLAG_FULLMESH (1U << 3) + +/// Use this endpoint in reaction to ADD_ADDR, but only once. +#define MPTCPD_ADDR_FLAG_LAMINAR (1U << 5) ///@} /** diff --git a/man/mptcpd.8.in b/man/mptcpd.8.in index 7b3e344c..aea93628 100644 --- a/man/mptcpd.8.in +++ b/man/mptcpd.8.in @@ -72,8 +72,9 @@ is a comma separated list containing one or more of the flags .IR subflow , .IR signal , .IR backup , +.IR fullmesh , and -.I fullmesh +.IR laminar that plugins that deal with the in-kernel path manager may use when advertising addresses, e.g. .B --addr-flags=subflow diff --git a/plugins/path_managers/addr_adv.c b/plugins/path_managers/addr_adv.c index cfb66d4e..94f95019 100644 --- a/plugins/path_managers/addr_adv.c +++ b/plugins/path_managers/addr_adv.c @@ -54,7 +54,8 @@ static void update_limits(struct mptcpd_pm *pm, int delta) If the pm creates outgoing subflows, we assume this is the client side, and accepts add_addrs from the server. */ - if (pm->config->addr_flags & MPTCPD_ADDR_FLAG_SUBFLOW) + if (pm->config->addr_flags & + (MPTCPD_ADDR_FLAG_SUBFLOW | MPTCPD_ADDR_FLAG_LAMINAR)) _limits[1].limit = _limits[0].limit; int const result = mptcpd_kpm_set_limits(pm, diff --git a/src/configuration.c b/src/configuration.c index fc967a20..8394ebc9 100644 --- a/src/configuration.c +++ b/src/configuration.c @@ -121,6 +121,7 @@ static struct tok_entry const addr_flags_toks[] = { { MPTCPD_ADDR_FLAG_SIGNAL, "signal" }, { MPTCPD_ADDR_FLAG_BACKUP, "backup" }, { MPTCPD_ADDR_FLAG_FULLMESH, "fullmesh" }, + { MPTCPD_ADDR_FLAG_LAMINAR, "laminar" }, { 0, NULL }, }; diff --git a/src/netlink_pm_upstream.c b/src/netlink_pm_upstream.c index 4f43fae9..541a7242 100644 --- a/src/netlink_pm_upstream.c +++ b/src/netlink_pm_upstream.c @@ -34,7 +34,8 @@ #if MPTCPD_ADDR_FLAG_SIGNAL != MPTCP_PM_ADDR_FLAG_SIGNAL \ || MPTCPD_ADDR_FLAG_SUBFLOW != MPTCP_PM_ADDR_FLAG_SUBFLOW \ || MPTCPD_ADDR_FLAG_BACKUP != MPTCP_PM_ADDR_FLAG_BACKUP \ - || MPTCPD_ADDR_FLAG_FULLMESH != MPTCP_PM_ADDR_FLAG_FULLMESH + || MPTCPD_ADDR_FLAG_FULLMESH != MPTCP_PM_ADDR_FLAG_FULLMESH \ + || MPTCPD_ADDR_FLAG_LAMINAR != MPTCP_PM_ADDR_FLAG_LAMINAR # error Mismatch between mptcpd and upstream kernel addr flags. #endif From 2e9ed47fc492e18414676d572a2a3c8fea59c73d Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Thu, 9 Oct 2025 18:05:44 +0200 Subject: [PATCH 3/4] tests: commands: also check flags Endpoints are usually added with a flag: validate that. Set a random one (the new 'subflow' one) instead of 0. Signed-off-by: Matthieu Baerts (NGI0) --- tests/test-commands.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test-commands.c b/tests/test-commands.c index 6cad3b34..3203a72f 100644 --- a/tests/test-commands.c +++ b/tests/test-commands.c @@ -58,6 +58,9 @@ struct test_addr_info // MPTCP address ID used for add_addr and dump_addr calls. mptcpd_aid_t id; + + // MPTCP address flags used in the endpoints + mptcpd_flags_t const flags; }; struct test_info @@ -186,6 +189,7 @@ static void get_addr_callback(struct mptcpd_addr_info const *info, assert(mptcpd_addr_info_get_id(info) == k_addr->id); assert(mptcpd_addr_info_get_index(info) == k_addr->ifindex); + assert(mptcpd_addr_info_get_flags(info) == k_addr->flags); assert(sockaddr_is_equal(k_addr->addr, mptcpd_addr_info_get_addr(info))); } @@ -210,6 +214,7 @@ static void dump_addrs_callback(struct mptcpd_addr_info const *info, return; assert(mptcpd_addr_info_get_index(info) == k_addr->ifindex); + assert(mptcpd_addr_info_get_flags(info) == k_addr->flags); assert(sockaddr_is_equal(k_addr->addr, mptcpd_addr_info_get_addr(info))); } @@ -327,12 +332,10 @@ static void test_add_addr_kernel(void const *test_data) k_addr->id = mptcpd_idm_get_id(idm, k_addr->addr); - uint32_t flags = 0; - int const result = mptcpd_kpm_add_addr(pm, k_addr->addr, k_addr->id, - flags, + k_addr->flags, k_addr->ifindex); assert(result == 0 || result == ENOTSUP); @@ -911,7 +914,8 @@ static void test_commands(void const *data) .k_addr = { .addr = (struct sockaddr *) &kernel_addr, .ifindex = if_nametoindex(loopback), - .prefix_len = get_prefix_len(info.k_addr.addr) + .prefix_len = get_prefix_len(info.k_addr.addr), + .flags = MPTCPD_ADDR_FLAG_SUBFLOW } }; From 68c2614c418293ba489e95ddcdfce57c35514041 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Thu, 9 Oct 2025 18:24:33 +0200 Subject: [PATCH 4/4] tests: config: check --addr-flags This parameter was not validated before. Use all possible flags (even if they are not individually checked). Signed-off-by: Matthieu Baerts (NGI0) --- tests/test-configuration.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test-configuration.c b/tests/test-configuration.c index 5623a3f0..d2508d36 100644 --- a/tests/test-configuration.c +++ b/tests/test-configuration.c @@ -108,6 +108,17 @@ static void test_load_plugins(void const *test_data) RUN_CONFIG(argv); } +static void test_addr_flags(void const *test_data) +{ + (void) test_data; + + static char *argv[] = + { TEST_PROGRAM_NAME, "--addr-flags", + "signal,subflow,fullmesh,backup,laminar" }; + + RUN_CONFIG(argv); +} + static void test_multi_arg(void const *test_data) { (void) test_data; @@ -176,6 +187,7 @@ int main(int argc, char *argv[]) l_test_add("plugin dir", test_plugin_dir, NULL); l_test_add("path manager", test_path_manager, NULL); l_test_add("load plugins", test_load_plugins, NULL); + l_test_add("addr flags", test_addr_flags, NULL); l_test_add("multi arg", test_multi_arg, NULL); l_test_add("config file", test_config_file, NULL); l_test_add("debug", test_debug, NULL);