From 3f69070598b569bf20f5c296ff21f861bfe003e3 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Mon, 20 May 2024 18:37:17 +0200 Subject: [PATCH] core/socket: allow MPTCP protocol Multipath TCP (MPTCP), standardized in RFC8684 [1], is a TCP extension that enables a TCP connection to use different paths. It allows a device to make use of multiple interfaces at once to send and receive TCP packets over a single MPTCP connection. MPTCP can aggregate the bandwidth of multiple interfaces or prefer the one with the lowest latency, it also allows a fail-over if one path is down, and the traffic is seamlessly re-injected on other paths. To benefit from MPTCP, both the client and the server have to support it. Multipath TCP is a backward-compatible TCP extension that is enabled by default on recent Linux distributions (Debian, Ubuntu, Redhat, ...). Multipath TCP is included in the Linux kernel since version 5.6 [2]. To use it on Linux, an application must explicitly enable it when creating the socket: int sd = socket(AF_INET(6), SOCK_STREAM, IPPROTO_MPTCP); No need to change anything else in the application. This patch allows MPTCP protocol in the Socket unit configuration. So now, a .socket can contain this to use MPTCP instead of TCP: [Socket] SocketProtocol=mptcp MPTCP support has been allowed similarly to what has been already done to allow SCTP: just one line in core/socket.c, a very simple addition thanks to the flexible architecture already in place. On top of that, IPPROTO_MPTCP has also been added in the list of allowed protocols in two other places, and in the doc. It has also been added to the missing_network.h file, for systems with an old libc -- note that it was also required to include in this file to avoid redefinition errors. Link: https://www.rfc-editor.org/rfc/rfc8684.html [1] Link: https://www.mptcp.dev [2] --- man/systemd.socket.xml | 9 +++++---- src/basic/missing_network.h | 7 +++++++ src/core/dbus-socket.c | 2 +- src/core/load-fragment.c | 2 +- src/core/socket.c | 4 ++++ src/test/test-ip-protocol-list.c | 2 ++ test/fuzz/fuzz-unit-file/syslog.socket | 1 + 7 files changed, 21 insertions(+), 6 deletions(-) diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index aa0e661002..67384bfcc4 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -318,10 +318,11 @@ SocketProtocol= - Takes one of - or . The socket will use the UDP-Lite - (IPPROTO_UDPLITE) or SCTP - (IPPROTO_SCTP) protocol, respectively. + Takes one of , + or . The socket will use + the UDP-Lite (IPPROTO_UDPLITE), SCTP + (IPPROTO_SCTP) or MPTCP + (IPPROTO_MPTCP) protocol, respectively. diff --git a/src/basic/missing_network.h b/src/basic/missing_network.h index 776c7c8375..ff5b30d3e1 100644 --- a/src/basic/missing_network.h +++ b/src/basic/missing_network.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + /* linux/in6.h or netinet/in.h */ #ifndef IPV6_UNICAST_IF #define IPV6_UNICAST_IF 76 @@ -11,6 +13,11 @@ #define IPV6_TRANSPARENT 75 #endif +/* linux/in.h or netinet/in.h */ +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif + /* Not exposed but defined at include/net/ip.h */ #ifndef IPV4_MIN_MTU #define IPV4_MIN_MTU 68 diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 03c5b4ad2a..320a93e981 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -131,7 +131,7 @@ static const char* socket_protocol_to_string(int32_t i) { if (i == IPPROTO_IP) return ""; - if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP)) + if (!IN_SET(i, IPPROTO_UDPLITE, IPPROTO_SCTP, IPPROTO_MPTCP)) return NULL; return ip_protocol_to_name(i); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 5ae68886af..4ff1e66d7b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -81,7 +81,7 @@ static int parse_socket_protocol(const char *s) { r = parse_ip_protocol(s); if (r < 0) return r; - if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP)) + if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP, IPPROTO_MPTCP)) return -EPROTONOSUPPORT; return r; diff --git a/src/core/socket.c b/src/core/socket.c index 41147d4bf7..726b805d43 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1645,6 +1645,10 @@ static int socket_open_fds(Socket *orig_s) { switch (p->address.type) { case SOCK_STREAM: + if (IN_SET(s->socket_protocol, IPPROTO_SCTP, IPPROTO_MPTCP)) + p->address.protocol = s->socket_protocol; + break; + case SOCK_SEQPACKET: if (s->socket_protocol == IPPROTO_SCTP) p->address.protocol = s->socket_protocol; diff --git a/src/test/test-ip-protocol-list.c b/src/test/test-ip-protocol-list.c index 9d0403c2f9..5077ae2360 100644 --- a/src/test/test-ip-protocol-list.c +++ b/src/test/test-ip-protocol-list.c @@ -54,6 +54,8 @@ TEST(string) { TEST(parse_ip_protocol) { assert_se(parse_ip_protocol("sctp") == IPPROTO_SCTP); assert_se(parse_ip_protocol("ScTp") == IPPROTO_SCTP); + assert_se(parse_ip_protocol("mptcp") == IPPROTO_MPTCP); + assert_se(parse_ip_protocol("MPTCP") == IPPROTO_MPTCP); assert_se(parse_ip_protocol("ip") == IPPROTO_IP); assert_se(parse_ip_protocol("") == IPPROTO_IP); assert_se(parse_ip_protocol("1") == 1); diff --git a/test/fuzz/fuzz-unit-file/syslog.socket b/test/fuzz/fuzz-unit-file/syslog.socket index bb046a5c6f..daf9743452 100644 --- a/test/fuzz/fuzz-unit-file/syslog.socket +++ b/test/fuzz/fuzz-unit-file/syslog.socket @@ -58,6 +58,7 @@ ListenMessageQueue= ListenUSBFunction= SocketProtocol=udplite SocketProtocol=sctp +SocketProtocol=mptcp SocketProtocol= BindIPv6Only=false Backlog=33 -- 2.25.1