Skip to content

Commit

Permalink
Add Multipath TCP (MPTCP) support (Core)
Browse files Browse the repository at this point in the history
Multipath TCP (MPTCP), standardized in RFC8684 [1],
is a TCP extension that enables a TCP connection to
use different paths.

Multipath TCP has been used for several use cases.
On smartphones, MPTCP enables seamless handovers between
cellular and Wi-Fi networks while preserving established
connections. This use-case is what pushed Apple to use
MPTCP since 2013 in multiple applications [2]. On dual-stack
hosts, Multipath TCP enables the TCP connection to
automatically use the best performing path, either IPv4
or IPv6. If one path fails, MPTCP automatically uses
the other path.

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 [3].
To use it on Linux, an application must explicitly enable
it when creating the socket. No need to change anything
else in the application.

Adding the possibility to create MPTCP sockets would thus
be a really fine addition to httpd, by allowing clients
to make use of their different interfaces.

This patch introduces the possibility to listen with MPTCP
sockets. Note however that these changes are only available
on Linux, as IPPROTO_MPTCP is Linux specific for the time being.

To do so, we extended the Listen directive to include
a "multipathtcp" option, allowing to create MPTCP sockets
instead of regular TCP ones:

Listen 80 options=multipathtcp

We then store this information in flags for the listen directive
and create sockets appropriately according to this value.

Link: https://www.rfc-editor.org/rfc/rfc8684.html [1]
Link: https://www.tessares.net/apples-mptcp-story-so-far/ [2]
Link: https://www.mptcp.dev [3]
  • Loading branch information
Aperence authored and notroj committed Aug 30, 2024
1 parent dfa6aec commit 0d56d53
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 2 deletions.
6 changes: 6 additions & 0 deletions docs/manual/mod/mpm_common.xml
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@ Listen 192.170.2.5:8000
to the same port. (If the server is built with IPv4-mapped
addresses <em>disabled</em>, this is the default behaviour and
this option has no effect.)</li>

<li><code>multipathtcp</code>: Enable the use of
<a href="https://mptcp.dev">Multipath TCP (MPTCP)</a> for the
sockets. Beware that this option is currently limited to Linux
only.
</li>
</ul>

<note><title>Error condition</title>
Expand Down
1 change: 1 addition & 0 deletions include/ap_listen.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef apr_status_t (*accept_function)(void **csd, ap_listen_rec *lr, apr_pool_
#define AP_LISTEN_FREEBIND (0x0002)
#define AP_LISTEN_REUSEPORT (0x0004)
#define AP_LISTEN_V6ONLY (0x0008)
#define AP_LISTEN_MPTCP (0x0010)

/**
* @brief Apache's listeners record.
Expand Down
22 changes: 20 additions & 2 deletions server/listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,12 @@ static const char *alloc_listener(process_rec *process, const char *addr,

while (sa) {
ap_listen_rec *new;
int sock_proto = 0;

#ifdef IPPROTO_MPTCP
if (flags & AP_LISTEN_MPTCP)
sock_proto = IPPROTO_MPTCP;
#endif

/* this has to survive restarts */
new = apr_palloc(process->pool, sizeof(ap_listen_rec));
Expand All @@ -509,7 +515,7 @@ static const char *alloc_listener(process_rec *process, const char *addr,
sa = sa->next;

status = apr_socket_create(&new->sd, new->bind_addr->family,
SOCK_STREAM, 0, process->pool);
SOCK_STREAM, sock_proto, process->pool);

#if APR_HAVE_IPV6
/* What could happen is that we got an IPv6 address, but this system
Expand Down Expand Up @@ -864,6 +870,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
char *hostname;
apr_port_t port;
apr_sockaddr_t *sa;
int sock_proto = 0;
#ifdef HAVE_SYSTEMD
if (use_systemd) {
int thesock;
Expand Down Expand Up @@ -891,8 +898,12 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
duplr->bind_addr = sa;
duplr->next = NULL;
duplr->flags = lr->flags;
#ifdef IPPROTO_MPTCP
if (duplr->flags & AP_LISTEN_MPTCP)
sock_proto = IPPROTO_MPTCP;
#endif
stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family,
SOCK_STREAM, 0, p);
SOCK_STREAM, sock_proto, p);
if (stat != APR_SUCCESS) {
ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(02640)
"ap_duplicate_listeners: for address %pI, "
Expand Down Expand Up @@ -1038,6 +1049,13 @@ static const char *parse_listen_flags(apr_pool_t *temp_pool, const char *arg,
flags |= AP_LISTEN_REUSEPORT;
else if (ap_cstr_casecmp(token, "v6only") == 0)
flags |= AP_LISTEN_V6ONLY;
else if (ap_cstr_casecmp(token, "multipathtcp") == 0)
#ifdef IPPROTO_MPTCP
flags |= AP_LISTEN_MPTCP;
#else
return apr_psprintf(temp_pool, "Listen option '%s' in '%s' is not supported on this system",
token, arg);
#endif
else
return apr_psprintf(temp_pool, "Unknown Listen option '%s' in '%s'",
token, arg);
Expand Down

0 comments on commit 0d56d53

Please sign in to comment.