v1-0001-Add-MPTCP-protocol-support-to-server-and-libpq-on.patch
application/octet-stream
Filename: v1-0001-Add-MPTCP-protocol-support-to-server-and-libpq-on.patch
Type: application/octet-stream
Part: 0
From e9855281fc14ab475362eb32b697a82b18259ff5 Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
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
</listitem>
</varlistentry>
+ <varlistentry id="libpq-connect-mptcp" xreflabel="mptcp">
+ <term><literal>MPTCP</literal><indexterm><primary>MultiPath TCP</primary></indexterm></term>
+ <listitem>
+ <para>
+ 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.
+ </para>
+
+ <para>
+ MPTCP protocol is only supported on Linux and allows connection aggregation
+ (multiplexing) over mulitple network paths, provided that remote also
+ supports MPTCP.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
</sect2>
@@ -9178,6 +9194,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
</para>
</listitem>
+ <listitem>
+ <para>
+ <indexterm>
+ <primary><envar>PGMPTCP</envar></primary>
+ </indexterm>
+ <envar>PGMPTCP</envar> behaves the same as the <xref
+ linkend="libpq-connect-mptcp"/> connection parameter.
+ </para>
+ </listitem>
+
<listitem>
<para>
<indexterm>
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