From e9855281fc14ab475362eb32b697a82b18259ff5 Mon Sep 17 00:00:00 2001 From: Jakub Wartak Date: Thu, 4 Sep 2025 11:39:54 +0200 Subject: [PATCH v1] Add MPTCP protocol support to server and libpq on Linux. This adds new listen_mptcp configuration option and also exposes new enviornimental variable PGMPTCP, which can be enabled to request MultiPathed TCP connection. --- doc/src/sgml/libpq.sgml | 26 +++++++++++++++++++++++ src/backend/libpq/pqcomm.c | 20 ++++++++++++++++- src/backend/postmaster/postmaster.c | 3 +++ src/backend/utils/misc/guc_parameters.dat | 6 ++++++ src/include/postmaster/postmaster.h | 1 + src/interfaces/libpq/fe-connect.c | 17 ++++++++++++++- src/interfaces/libpq/libpq-int.h | 1 + 7 files changed, 72 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 5bf59a19855..6e114477f8a 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -2568,6 +2568,22 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + MPTCPMultiPath TCP + + + Controls whether client-side MPTCP protocol is used. The default + value is 0, meaning off, but you can change this to 1, meaning on. + This parameter is ignored for connections made via a Unix-domain socket. + + + + MPTCP protocol is only supported on Linux and allows connection aggregation + (multiplexing) over mulitple network paths, provided that remote also + supports MPTCP. + + + @@ -9178,6 +9194,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) + + + + PGMPTCP + + PGMPTCP behaves the same as the connection parameter. + + + diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 25f739a6a17..8cddc96b004 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -438,6 +438,15 @@ ListenServerPort(int family, const char *hostName, unsigned short portNumber, int one = 1; #endif +#ifndef IPPROTO_MPTCP + if (ListenMPTCP) + { + ereport(WARNING, + (errmsg("setting the MPTCP listening socket is not supported on this platform"))); + return STATUS_ERROR; + } +#endif + /* Initialize hint structure */ MemSet(&hint, 0, sizeof(hint)); hint.ai_family = family; @@ -487,6 +496,8 @@ ListenServerPort(int family, const char *hostName, unsigned short portNumber, for (addr = addrs; addr; addr = addr->ai_next) { + int ipprotocol = 0; + if (family != AF_UNIX && addr->ai_family == AF_UNIX) { /* @@ -538,7 +549,14 @@ ListenServerPort(int family, const char *hostName, unsigned short portNumber, addrDesc = addrBuf; } - if ((fd = socket(addr->ai_family, SOCK_STREAM, 0)) == PGINVALID_SOCKET) + /* + * enable MPTCP only on IP and IPv6 sockets and not for UNIX domain + * sockets + */ + if (addr->ai_family != AF_UNIX) + ipprotocol = ListenMPTCP ? IPPROTO_MPTCP : 0; + + if ((fd = socket(addr->ai_family, SOCK_STREAM, ipprotocol)) == PGINVALID_SOCKET) { ereport(LOG, (errcode_for_socket_access(), diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index e1d643b013d..07b388e88b5 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -208,6 +208,9 @@ char *Unix_socket_directories; /* The TCP listen address(es) */ char *ListenAddresses; +/* Whether to use MPTCP */ +bool ListenMPTCP; + /* * SuperuserReservedConnections is the number of backends reserved for * superuser use, and ReservedConnections is the number of backends reserved diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat index a157cec3c4d..257b288aaee 100644 --- a/src/backend/utils/misc/guc_parameters.dat +++ b/src/backend/utils/misc/guc_parameters.dat @@ -351,6 +351,12 @@ boot_val => 'DEFAULT_ASSERT_ENABLED', }, +{ name => 'listen_mptcp', type => 'bool', context => 'PGC_POSTMASTER', group => 'CONN_AUTH_SETTINGS', + short_desc => 'Whether to enable MPTCP on the listening socket', + variable => 'ListenMPTCP', + boot_val => 'false', +}, + { name => 'exit_on_error', type => 'bool', context => 'PGC_USERSET', group => 'ERROR_HANDLING_OPTIONS', short_desc => 'Terminate session on any error.', variable => 'ExitOnAnyError', diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h index 92497cd6a0f..ca4cf7ea295 100644 --- a/src/include/postmaster/postmaster.h +++ b/src/include/postmaster/postmaster.h @@ -60,6 +60,7 @@ extern PGDLLIMPORT int Unix_socket_permissions; extern PGDLLIMPORT char *Unix_socket_group; extern PGDLLIMPORT char *Unix_socket_directories; extern PGDLLIMPORT char *ListenAddresses; +extern PGDLLIMPORT bool ListenMPTCP; extern PGDLLIMPORT bool ClientAuthInProgress; extern PGDLLIMPORT int PreAuthDelay; extern PGDLLIMPORT int AuthenticationTimeout; diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index a3d12931fff..abe045ec474 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -415,6 +415,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "SSL-Key-Log-File", "D", 64, offsetof(struct pg_conn, sslkeylogfile)}, + {"mptcp", "PGMPTCP", "0", NULL, + "MPTCP-Protocol", "", 1, + offsetof(struct pg_conn, mptcp)}, + /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0} @@ -3236,6 +3240,7 @@ keep_going: /* We will come back to here until there is char host_addr[NI_MAXHOST]; int sock_type; AddrInfo *addr_cur; + int ip_protocol = 0; /* * Advance to next possible host, if we've tried all of @@ -3321,7 +3326,17 @@ keep_going: /* We will come back to here until there is */ sock_type |= SOCK_NONBLOCK; #endif - conn->sock = socket(addr_cur->family, sock_type, 0); + + /* + * enable MPTCP only on IP and IPv6 sockets and not for + * UNIX domain sockets + */ + if (addr_cur->family != AF_UNIX && conn->mptcp && conn->mptcp[0] == '1') + { + fprintf(stderr, "enabling MPTCP client\n"); + ip_protocol = IPPROTO_MPTCP; + } + conn->sock = socket(addr_cur->family, sock_type, ip_protocol); if (conn->sock == PGINVALID_SOCKET) { int errorno = SOCK_ERRNO; diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 02c114f1405..976c6554803 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -430,6 +430,7 @@ struct pg_conn char *scram_client_key; /* base64-encoded SCRAM client key */ char *scram_server_key; /* base64-encoded SCRAM server key */ char *sslkeylogfile; /* where should the client write ssl keylogs */ + char *mptcp; /* use MPTCP ? */ bool cancelRequest; /* true if this connection is used to send a * cancel request, instead of being a normal -- 2.39.5