{"thread":{"id":"63476","subject":"PATCH v2 [1/1]: MPTCP support for Git on Linux","startedAt":"2025-05-17T17:02:41Z","lastAt":"2025-05-17T19:25:27Z","messageCount":4,"participants":["Muhammad Nuzaihan","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"518333","messageId":"6O0FWS.8JJP67DO2U1M1@unrealasia.net","threadId":"63476","inReplyTo":null,"subject":"PATCH v2 [1/1]: MPTCP support for Git on Linux","fromName":"Muhammad Nuzaihan","fromEmail":"zaihan@unrealasia.net","sentAt":"2025-05-17T17:02:30Z","receivedAt":"2025-05-17T17:02:41Z","isPatch":false,"sender":{"key":"zaihan@unrealasia.net","avatar":"https://gravatar.com/avatar/ec76e57992cf391eef4176d86e3cc48967bfe9842ee754a2ce0ac59c58308ed9?d=mp&s=160"},"body":"Hi,\n\nThis patch is about Multi-Path TCP.\n\nMulti-Path TCP (MPTCP) had been in development for the past 15 years\nwhich started with MPTCP v0 (version 0) which initially had issues\nfor middleboxes and NAT Gateways.\n\nThe current iteration is MPTCP v1 which has a fallback mechanism to\nregular\nTCP to avoid issues with middleboxes and NAT Gateways.\n\nStarted to add this code change as a need as i have large git codebases\nwith around 50 gigabytes and i have multiple WAN links which i can\naggregate\nbandwidth across and even when network one path (even in between my\nCPE router\nto internet) is down, i will not get interrupted.\n\nAlso i am using a Linux laptop that has WiFi and 5G module. So this kind\nof adds my reason of adding support for git (on Linux)\n\nTo get MPTCP to be fully working, both ends of client and server must\nimplement\nMPTCP.\n\nMy implementation adds support for the basic git protocol.\n\nMPTCP helps in situations when one of my WAN links have a high latency\nand\nautomatically choose a link with a path with less latency.\n\nAlso, MPTCP aggregates the MPTCP connection by using subflows where two\nor more\nlinks can be utilised with subflows. A single flow of data can have\nmultiple\nsubflows across different IP interfaces and thus increases network\nthroughput.\n\nApple for example had been using MPTCP for their cloud services since\nMPTCP v0\nwhich had issues with middleboxes (not MPTCP v1) since 2013.\n\nThe downside, even though i had never experienced it for other\napplications\non Linux like Google Chromium[1], is that the fallback might induce\ndelays\nin connectivity, if i've read it somewhere which i cannot recall where.\n\nHow this patch works:\n\nThis patch enables MPTCP protocol option only when it's built on Linux\nwith\nIPPROTO_MPTCP support in netinet/in.h.\n\nOn Linux, if IPPROTO_MPTCP is not defined in netinet/in.h, it will\nskipped.\n\nIPPROTO_MPTCP should and never be enabled when it detects being built on\nan OS other than Linux with defined(__linux__) check.\n\nAnother challenge is that although \"getaddrinfo()\" is a POSIX function,\nnot all glibc \"getaddrinfo()\" implementation is written with\nIPPROTO_MPTCP support out of the box, especially on older glibc\nversions.\n\ngetaddrinfo() IPPROTO_MPTCP support had only been added to recent glibc\nin 2025 eventhough IPPROTO_MPTCP definition had been around for\nmuch longer in netinet/in.h.\n\nSo we run getaddrinfo() which is a code in glibc and check for errors,\nspecifically \"EAI_SOCKTYPE\" return value which tells us that the socket\ntype\nis not supported and fallback to regular TCP (IPPROTO_TCP)\n\nAlso we will also check that we are building on Linux and depending on\nversion number of Linux we will initialize the socket() accordingly and\nif\nthere is an error return value (like\nEINVAL/EPROTONOSUPPORT/ENOPROTOOPT),\nwe will fall back to regular TCP.\n\nEnabling and disabling MPTCP:\n\nBy default on the client side, MPTCP will not be enabled in git client,\nhowever MPTCP\ncan be enabled by setting an environment variable \"GIT_ENABLE_MPTCP\" to\nany value.\n\nPersisting the configuration can be done in your shell.\n\nAlso for server side git server (daemon.c), there is a flag to\noptionally\nenable mptcp with \"--mptcp\", example:\n\ngit-daemon --base-path=/all/my/repos --export-all --mptcp\n\nThis will tell the git server daemon to accept mptcp connections but\nfallback to regular tcp when mptcp connection is not available.\n\nPS: Can someone point me about having a \"knob\" in Makefile or is this\nalready sufficient?\n\n[1] https://chromium-review.googlesource.com/c/chromium/src/+/6355767\n\nSigned-off-by: Muhammad Nuzaihan Bin Kamal Luddin\n<zaihan@unrealasia.net>\n\n\n\ndiff --git a/connect.c b/connect.c\nindex 3280435331..846fa31853 100644\n--- a/connect.c\n+++ b/connect.c\n@@ -23,6 +23,9 @@\n #include \"alias.h\"\n #include \"bundle-uri.h\"\n #include \"promisor-remote.h\"\n+#ifdef __linux__\n+#include <linux/version.h>\n+#endif\n \n static char *server_capabilities_v1;\n static struct strvec server_capabilities_v2 = STRVEC_INIT;\n@@ -793,6 +796,16 @@ static void enable_keepalive(int sockfd)\n \t\terror_errno(_(\"unable to set SO_KEEPALIVE on socket\"));\n }\n \n+static const char *git_enable_mptcp(void)\n+{\n+        const char *mptcp;\n+\n+        if ((mptcp = getenv(\"GIT_ENABLE_MPTCP\")))\n+                return mptcp;\n+\n+\treturn NULL;\n+}\n+\n #ifndef NO_IPV6\n \n static const char *ai_name(const struct addrinfo *ai)\n@@ -816,6 +829,7 @@ static int git_tcp_connect_sock(char *host, int flags)\n \tstruct addrinfo hints, *ai0, *ai;\n \tint gai;\n \tint cnt = 0;\n+\tconst char *enable_mptcp;\n \n \tget_host_and_port(&host, &port);\n \tif (!*port)\n@@ -827,12 +841,28 @@ static int git_tcp_connect_sock(char *host, int flags)\n \telse if (flags & CONNECT_IPV6)\n \t\thints.ai_family = AF_INET6;\n \thints.ai_socktype = SOCK_STREAM;\n-\thints.ai_protocol = IPPROTO_TCP;\n+#if defined(__linux__) && defined(IPPROTO_MPTCP)\n+        enable_mptcp = git_enable_mptcp();\n+\tif (enable_mptcp)\n+                hints.ai_protocol = IPPROTO_MPTCP;\n+\telse\n+                hints.ai_protocol = IPPROTO_TCP;\n+#else\n+        hints.ai_protocol = IPPROTO_TCP;\n+#endif\n \n \tif (flags & CONNECT_VERBOSE)\n \t\tfprintf(stderr, _(\"Looking up %s ... \"), host);\n \n-\tgai = getaddrinfo(host, port, &hints, &ai);\n+        gai = getaddrinfo(host, port, &hints, &ai);\n+        // If system's glibc getaddrinfo() does not have\n+        // IPPROTO_MPTCP as member type in struct (like older\n+        // glibc and other libc), we fallback to IPPROTO_TCP\n+        if (gai == EAI_SOCKTYPE) {\n+                hints.ai_protocol = IPPROTO_TCP;\n+                gai = getaddrinfo(host, port, &hints, &ai);\n+        }\n+\t\n \tif (gai)\n \t\tdie(_(\"unable to look up %s (port %s) (%s)\"), host, port, gai_strerror(gai));\n \n@@ -889,6 +919,7 @@ static int git_tcp_connect_sock(char *host, int flags)\n \tchar **ap;\n \tunsigned int nport;\n \tint cnt;\n+\tconst char *enable_mptcp;\n \n \tget_host_and_port(&host, &port);\n \n@@ -917,6 +948,21 @@ static int git_tcp_connect_sock(char *host, int flags)\n \t\tsa.sin_port = htons(nport);\n \t\tmemcpy(&sa.sin_addr, *ap, he->h_length);\n \n+#ifdef __linux__\n+\t\tenable_mptcp = git_enable_mptcp(); \n+\t\tif (enable_mptcp) {\n+                        sockfd = socket(he->h_addrtype, SOCK_STREAM, IPPROTO_MPTCP);\n+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)\n+                        // MPTCP check return value for Linux Kernel >= 5.6\n+                        if (sockfd == EPROTONOSUPPORT || sockfd == ENOPROTOOPT)\n+                                continue;\n+#else\n+                        // MPTCP check return value for Linux Kernel < 5.6\n+                        if (sockfd == EINVAL || sockfd == ENOPROTOOPT)\n+                                continue;\n+#endif\n+                }\n+#endif\n \t\tsockfd = socket(he->h_addrtype, SOCK_STREAM, 0);\n \t\tif ((sockfd < 0) ||\n \t\t    connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {\ndiff --git a/daemon.c b/daemon.c\nindex d1be61fd57..793f8a4219 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -25,6 +25,7 @@ static enum log_destination {\n } log_destination = LOG_DESTINATION_UNSET;\n static int verbose;\n static int reuseaddr;\n+static int mptcp;\n static int informative_errors;\n \n static const char daemon_usage[] =\n@@ -38,6 +39,7 @@ static const char daemon_usage[] =\n \"           [--access-hook=<path>]\\n\"\n \"           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\\n\"\n \"                      [--detach] [--user=<user> [--group=<group>]]\\n\"\n+\"           [--mptcp]\\n\"\n \"           [--log-destination=(stderr|syslog|none)]\\n\"\n \"           [<directory>...]\";\n \n@@ -975,10 +977,24 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis\n \tmemset(&hints, 0, sizeof(hints));\n \thints.ai_family = AF_UNSPEC;\n \thints.ai_socktype = SOCK_STREAM;\n-\thints.ai_protocol = IPPROTO_TCP;\n+#if defined(__linux__) && defined(IPPROTO_MPTCP)\n+\tif (mptcp)\n+                hints.ai_protocol = IPPROTO_MPTCP;\n+        else\n+                hints.ai_protocol = IPPROTO_MPTCP;\n+#else\n+        hints.ai_protocol = IPPROTO_TCP;\n+#endif\n \thints.ai_flags = AI_PASSIVE;\n \n-\tgai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);\n+        gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);\n+        // If system's glibc getaddrinfo() does not have\n+        // IPPROTO_MPTCP as member type in struct (like older\n+        // glibc and other libc), we fallback to IPPROTO_TCP\n+        if (gai == EAI_SOCKTYPE) {\n+                hints.ai_protocol = IPPROTO_TCP;\n+                gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);\n+        }\n \tif (gai) {\n \t\tlogerror(\"getaddrinfo() for %s failed: %s\", listen_addr, gai_strerror(gai));\n \t\treturn 0;\n@@ -1342,6 +1358,10 @@ int cmd_main(int argc, const char **argv)\n \t\t\treuseaddr = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--mptcp\")) {\n+\t\t\tmptcp = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--user-path\")) {\n \t\t\tuser_path = \"\";\n \t\t\tcontinue;\n"},{"id":"518336","messageId":"9R4FWS.9NR30V555Q5S@unrealasia.net","threadId":"63476","inReplyTo":"6O0FWS.8JJP67DO2U1M1@unrealasia.net","subject":"Re: PATCH v3 [1/1]: MPTCP support for Git on Linux","fromName":"Muhammad Nuzaihan","fromEmail":"zaihan@unrealasia.net","sentAt":"2025-05-17T18:30:45Z","receivedAt":"2025-05-17T18:31:33Z","isPatch":false,"sender":{"key":"zaihan@unrealasia.net","avatar":"https://gravatar.com/avatar/ec76e57992cf391eef4176d86e3cc48967bfe9842ee754a2ce0ac59c58308ed9?d=mp&s=160"},"body":"Hi,\n\nThis code below in v2:\n\n+#if defined(__linux__) && defined(IPPROTO_MPTCP)\n+ if (mptcp)\n+ hints.ai_protocol = IPPROTO_MPTCP;\n+ else\n+ hints.ai_protocol = IPPROTO_MPTCP;\n+#else\n+ hints.ai_protocol = IPPROTO_TCP;\n+#endif\n\nHas a small bug, which i realised in the v2 patch while debugging the\ntraffic with wireshark.\n\nSo i'm correcting this minor mistake where the else statement\nshould fallback to regular TCP if flag is disabled in v3:\n\n+#if defined(__linux__) && defined(IPPROTO_MPTCP)\n+ if (mptcp)\n+ hints.ai_protocol = IPPROTO_MPTCP;\n+ else\n+ hints.ai_protocol = IPPROTO_TCP;\n+#else\n+ hints.ai_protocol = IPPROTO_TCP;\n+#endif\n\nChanges in v3:\n- fix a bug with regards to mptcp flag should switch to regular TCP if \nfalse.\n\nChanges in v2:\n- Check for whether git is being built for Linux and also if it's on \nLinux, check if\n  IPPROTO_MPTCP exists in both connect.c (client) and daemon.c (server)\n- Check for whether the glibc version support IPPROTO_MPTCP in \ngetaddrinfo() function,\n  old versions of glibc does not support this even though header \ndefinitions netinet/in.h\n  had already for years. Running getaddinfo() will return EAI_SOCKTYPE \nerror\n  if IPPROTO_MPTCP is not supported and we fallback to regular TCP.\n- In both client side (connect.c) and server side (daemon.c) check if \nsocket() supports\n  IPPROTO_MPTCP if the git is built in Linux including checks for \nversion 5.6\n  and above and below 5.6 for proper error return values,\n  else skip and run regular TCP (IPPROTO_TCP)\n- Add client side enable/diable environment variable option \nGIT_ENABLE_MPTCP\n  for client side (connect.c) to enable/disable MPTCP on client side.\n- Add git server side enable/disable flag \"--mptcp\" to enable or \ndisable server/side MPTCP.\n\nLink to v2: \nhttps://lore.kernel.org/git/6O0FWS.8JJP67DO2U1M1@unrealasia.net/T/#u\nLink to v1: \nhttps://lore.kernel.org/git/a76dda61-f60c-4221-83db-5e165a2478b1@gmail.com/T/#t\n\nSigned-off-by: Muhammad Nuzaihan Bin Kamal Luddin\n<zaihan@unrealasia.net>\n\nOn Sun, May 18 2025 at 01:02:30 AM +0800, Muhammad Nuzaihan \n<zaihan@unrealasia.net> wrote:\n> Hi,\n> \n> This patch is about Multi-Path TCP.\n> \n> Multi-Path TCP (MPTCP) had been in development for the past 15 years\n> which started with MPTCP v0 (version 0) which initially had issues\n> for middleboxes and NAT Gateways.\n> \n> The current iteration is MPTCP v1 which has a fallback mechanism to\n> regular\n> TCP to avoid issues with middleboxes and NAT Gateways.\n> \n> Started to add this code change as a need as i have large git \n> codebases\n> with around 50 gigabytes and i have multiple WAN links which i can\n> aggregate\n> bandwidth across and even when network one path (even in between my\n> CPE router\n> to internet) is down, i will not get interrupted.\n> \n> Also i am using a Linux laptop that has WiFi and 5G module. So this \n> kind\n> of adds my reason of adding support for git (on Linux)\n> \n> To get MPTCP to be fully working, both ends of client and server must\n> implement\n> MPTCP.\n> \n> My implementation adds support for the basic git protocol.\n> \n> MPTCP helps in situations when one of my WAN links have a high latency\n> and\n> automatically choose a link with a path with less latency.\n> \n> Also, MPTCP aggregates the MPTCP connection by using subflows where \n> two\n> or more\n> links can be utilised with subflows. A single flow of data can have\n> multiple\n> subflows across different IP interfaces and thus increases network\n> throughput.\n> \n> Apple for example had been using MPTCP for their cloud services since\n> MPTCP v0\n> which had issues with middleboxes (not MPTCP v1) since 2013.\n> \n> The downside, even though i had never experienced it for other\n> applications\n> on Linux like Google Chromium[1], is that the fallback might induce\n> delays\n> in connectivity, if i've read it somewhere which i cannot recall \n> where.\n> \n> How this patch works:\n> \n> This patch enables MPTCP protocol option only when it's built on Linux\n> with\n> IPPROTO_MPTCP support in netinet/in.h.\n> \n> On Linux, if IPPROTO_MPTCP is not defined in netinet/in.h, it will\n> skipped.\n> \n> IPPROTO_MPTCP should and never be enabled when it detects being built \n> on\n> an OS other than Linux with defined(__linux__) check.\n> \n> Another challenge is that although \"getaddrinfo()\" is a POSIX \n> function,\n> not all glibc \"getaddrinfo()\" implementation is written with\n> IPPROTO_MPTCP support out of the box, especially on older glibc\n> versions.\n> \n> getaddrinfo() IPPROTO_MPTCP support had only been added to recent \n> glibc\n> in 2025 eventhough IPPROTO_MPTCP definition had been around for\n> much longer in netinet/in.h.\n> \n> So we run getaddrinfo() which is a code in glibc and check for errors,\n> specifically \"EAI_SOCKTYPE\" return value which tells us that the \n> socket\n> type\n> is not supported and fallback to regular TCP (IPPROTO_TCP)\n> \n> Also we will also check that we are building on Linux and depending on\n> version number of Linux we will initialize the socket() accordingly \n> and\n> if\n> there is an error return value (like\n> EINVAL/EPROTONOSUPPORT/ENOPROTOOPT),\n> we will fall back to regular TCP.\n> \n> Enabling and disabling MPTCP:\n> \n> By default on the client side, MPTCP will not be enabled in git \n> client,\n> however MPTCP\n> can be enabled by setting an environment variable \"GIT_ENABLE_MPTCP\" \n> to\n> any value.\n> \n> Persisting the configuration can be done in your shell.\n> \n> Also for server side git server (daemon.c), there is a flag to\n> optionally\n> enable mptcp with \"--mptcp\", example:\n> \n> git-daemon --base-path=/all/my/repos --export-all --mptcp\n> \n> This will tell the git server daemon to accept mptcp connections but\n> fallback to regular tcp when mptcp connection is not available.\n> \n> PS: Can someone point me about having a \"knob\" in Makefile or is this\n> already sufficient?\n> \n> [1] https://chromium-review.googlesource.com/c/chromium/src/+/6355767\n> \n> Signed-off-by: Muhammad Nuzaihan Bin Kamal Luddin\n> <zaihan@unrealasia.net>\n> \n\n\n"},{"id":"518339","messageId":"xmqq5xhzqdmz.fsf@gitster.g","threadId":"63476","inReplyTo":"6O0FWS.8JJP67DO2U1M1@unrealasia.net","subject":"Re: PATCH v2 [1/1]: MPTCP support for Git on Linux","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-05-17T18:46:12Z","receivedAt":"2025-05-17T18:46:16Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Muhammad Nuzaihan <zaihan@unrealasia.net> writes:\n\n> Hi,\n>\n> This patch is about Multi-Path TCP.\n\nPerhaps reading and following Documentation/SubmittingPatches and\npossibly MyFirstContribution is in order.\n\nHow widely is MPTCP adopted?  I somehow feel that it is a losing\nproposition to _require_ that each and every _application_ to be\nupdated to support it, but say if we take a random set of widely\nused application, how much of them have specific knowledge of how\nto work with MPTCP these days?\n\n\n\n"},{"id":"518341","messageId":"4A7FWS.KARM6LOQBQ5S3@unrealasia.net","threadId":"63476","inReplyTo":"xmqq5xhzqdmz.fsf@gitster.g","subject":"Re: PATCH v2 [1/1]: MPTCP support for Git on Linux","fromName":"Muhammad Nuzaihan","fromEmail":"zaihan@unrealasia.net","sentAt":"2025-05-17T19:25:16Z","receivedAt":"2025-05-17T19:25:27Z","isPatch":false,"sender":{"key":"zaihan@unrealasia.net","avatar":"https://gravatar.com/avatar/ec76e57992cf391eef4176d86e3cc48967bfe9842ee754a2ce0ac59c58308ed9?d=mp&s=160"},"body":"Hi Junio,\n\nMPTCP has been in development for 15 years and only reached maturity\nin v1 of the protocol.\n\nOnly recently in 2020 that this protocol (v1) was officially merged\ninto the Linux kernel mainline but before that Linux MPTCP was developed\nout-of-tree.\n\nApple had been using MPTCP in production for the\npast 12 years for their iOS[1] for Apple's cloud services.\n\nIt's no longer an experimental technology it's in the IETF standards \ntrack[2]\nand no longer in experimental track.\n\nI know it's cumbersome to implement MPTCP for every application out \nthere,\nthe same with IPv6 which already had been around for more than 20 years \nand still\nnot that widely adopted, especially for enterprises.\n\nBut i think we have to start somewhere. I myself had been working on \nIPv6\nsince 2003 and i think the late Jun Ichiro Hagino probably did the \nright thing\neven though people around him might think otherwise.\n\nAnyway, back to git. I think it will benefit the server side more with\naggregation but i started to work on this after realising how bad my \nhotel's wifi\nand i have a WWAN module and thought of aggregating my bandwidth.\n\nSince Go is enabled MPTCP by default in 1.24, it makes sense\nfor me to add more MPTCP support, at least on the Linux side of things. \nGo\nis really popular not just web services but also load balancers (which \ncan\nalso be TCP load balancers).\n\nI cannot vouch Linux kernel's MPTCP implementation as someone had \nmentioned\nabout the CVE because of backpressure but that CVE was in 2022, 3 years \nago.\n\nGo 1.24 with MPTCP by default is only released this year, so time will \ntell. :-)\n\nI think eventually just like IPv6, people will have knowledge on how it\nworks.\n\n[1]http://blog.multipath-tcp.org/blog/html/2018/12/15/apple_and_multipath_tcp.html\n[2]https://datatracker.ietf.org/doc/html/rfc8684\n\nRegards,\nZaihan\n\nOn Sat, May 17 2025 at 11:46:12 AM -0700, Junio C Hamano \n<gitster@pobox.com> wrote:\n> Muhammad Nuzaihan <zaihan@unrealasia.net> writes:\n> \n>>  Hi,\n>> \n>>  This patch is about Multi-Path TCP.\n> \n> Perhaps reading and following Documentation/SubmittingPatches and\n> possibly MyFirstContribution is in order.\n> \n> How widely is MPTCP adopted?  I somehow feel that it is a losing\n> proposition to _require_ that each and every _application_ to be\n> updated to support it, but say if we take a random set of widely\n> used application, how much of them have specific knowledge of how\n> to work with MPTCP these days?\n> \n> \n> \n\n\n"}]}