]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: haterm: Prepare support for splicing by initializing a master pipe
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 2 Apr 2026 19:31:53 +0000 (21:31 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 3 Apr 2026 08:46:15 +0000 (10:46 +0200)
Now the zero-copy data forwarding is supported, we will add the splicing
support. To do so, we first create a master pipe with vmsplice() during
haterm startup. It is only performed if the splicing is supported. And its
size can be configured by setting "tune.pipesize" global parameter.

This master pipe will be used to fill the pipe with the client.

src/haterm.c
src/haterm_init.c

index d4a2e80a404ebb6853d5c505c66152179c1d85b1..e66c41f23ee0fe27931476919ad36718dad0c229 100644 (file)
@@ -1,3 +1,6 @@
+#define _GNU_SOURCE
+#include <fcntl.h>
+
 #include <haproxy/buf.h>
 #include <haproxy/cfgparse.h>
 #include <haproxy/chunk.h>
@@ -6,6 +9,7 @@
 #include <haproxy/http_htx.h>
 #include <haproxy/http.h>
 #include <haproxy/istbuf.h>
+#include <haproxy/pipe.h>
 #include <haproxy/pool.h>
 #include <haproxy/proxy-t.h>
 #include <haproxy/sc_strm.h>
@@ -62,6 +66,11 @@ static char common_chunk_resp[RESPSIZE];
 static char *random_resp;
 static int random_resp_len = RESPSIZE;
 
+#if defined(USE_LINUX_SPLICE)
+struct pipe *master_pipe = NULL;
+size_t master_pipesize = 0;
+#endif
+
 static size_t hstream_add_ff_data(struct hstream *hs, struct sedesc *sd, unsigned long long len);
 static size_t hstream_add_htx_data(struct hstream *hs, struct htx *htx, unsigned long long len);
 
@@ -1158,4 +1167,55 @@ static int hstream_build_responses(void)
        return 1;
 }
 
+#if defined(USE_LINUX_SPLICE)
+static void hstream_init_splicing(void)
+{
+       if (!(global.tune.options & GTUNE_USE_SPLICE))
+               return;
+
+       if (!global.tune.pipesize)
+               global.tune.pipesize = 65536 * 5 / 4;
+
+       master_pipe = get_pipe();
+       if (master_pipe) {
+               struct iovec v = { .iov_base = common_response,
+                                  .iov_len = sizeof(common_response) };
+               int total, ret;
+
+               total = ret = 0;
+               do {
+                       ret = vmsplice(master_pipe->prod, &v, 1, SPLICE_F_NONBLOCK);
+                       if (ret > 0)
+                               total += ret;
+               } while (ret > 0 && total < global.tune.pipesize);
+               master_pipesize = total;
+
+               if (master_pipesize < global.tune.pipesize) {
+                       if (master_pipesize < 60*1024) {
+                               /* Older kernels were limited to around 60-61 kB */
+                               ha_warning("Failed to vmsplice response buffer after %lu bytes, splicing disabled\n", master_pipesize);
+                               global.tune.options &= ~GTUNE_USE_SPLICE;
+                               put_pipe(master_pipe);
+                               master_pipe = NULL;
+                       }
+                       else
+                               ha_warning("Splicing is limited to %lu bytes (too old kernel)\n", master_pipesize);
+               }
+       }
+       else {
+               ha_warning("Unable to allocate master pipe for splicing, splicing disabled\n");
+               global.tune.options &= ~GTUNE_USE_SPLICE;
+       }
+}
+
+static void hstream_deinit(void)
+{
+       if (master_pipe)
+               put_pipe(master_pipe);
+}
+
+REGISTER_POST_DEINIT(hstream_deinit);
+INITCALL0(STG_INIT_2, hstream_init_splicing);
+#endif
+
 REGISTER_POST_CHECK(hstream_build_responses);
index 94e8a96a1fefcf0bf06d47d6be49c784b82f02eb..797e636d27037c168879f9a4960c3bb8f722e248 100644 (file)
@@ -186,6 +186,10 @@ void haproxy_init_args(int argc, char **argv)
        /* save the arguments */
        sargc = argc; sargv = argv;
 
+#if defined(USE_LINUX_SPLICE)
+       global.tune.options |= GTUNE_USE_SPLICE;
+#endif
+
        /* THIS PART MUST NOT MODIFY THE ARGUMENTS */
        /* Parse the arguments which must be reused to build the conf. */
        while (argc > 0) {