]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: global: Add an option to disable the data fast-forward
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 14 Feb 2023 14:37:14 +0000 (15:37 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 17 Feb 2023 09:17:02 +0000 (10:17 +0100)
The new global option "tune.fast-forward" can be set to "off" to disable the
data fast-forward. It is an debug option, thus it is internally marked as
experimental. The directive "expose-experimental-directives" must be set
first to use this one. By default, the data fast-forward is enable.

It could be usefull to force to wake the stream up when data are
received. To be sure, evreything works fine in this case. The data
fast-forward is an optim. It must work without it. But some code may rely on
the fact the stream will not be woken up. With this option, it is possible
to spot some hidden bugs.

doc/configuration.txt
include/haproxy/global-t.h
src/cfgparse-global.c
src/http_ana.c
src/stream.c

index 9fad884a47f47d5b0dd2c631fc5e6919f31426f0..a778c4788b0ef5fe5fe7efc349c4395de87d86e5 100644 (file)
@@ -1123,6 +1123,7 @@ The following keywords are supported in the "global" section :
    - tune.buffers.reserve
    - tune.bufsize
    - tune.comp.maxlevel
+   - tune.fast-forward
    - tune.fd.edge-triggered
    - tune.h2.header-table-size
    - tune.h2.initial-window-size
@@ -2837,6 +2838,17 @@ tune.fail-alloc
   failure) and 100 (no success). This is useful to debug and make sure memory
   failures are handled gracefully.
 
+tune.fast-forward { on | off } [ EXPERIMENTAL ]
+
+  Enabled ('on') or disables ('off') the data fast-forwarding. It is a
+  mechanism to optimize the data forwarding by passing data directly from a
+  side to the other one without waking the stream up. Thanks to this directive,
+  it is possible to disable this optimization. Note it also disable any kernel
+  tcp splicing. This command is not meant for regular use, it will generally
+  only be suggested by developers along complex debugging sessions. For this
+  reason it is internally marked as experimental, meaning that
+  "expose-experimental-directives" must appear on a line before this directive.
+
 tune.fd.edge-triggered { on | off }  [ EXPERIMENTAL ]
   Enables ('on') or disables ('off') the edge-triggered polling mode for FDs
   that support it. This is currently only support with epoll. It may noticeably
index 30308c772b20e6ee8087508270cad4866d9723f7..c0ccc812e0ce6107ceb902bc6904b8fe7a25b56f 100644 (file)
@@ -80,6 +80,7 @@
 #define GTUNE_QUICK_EXIT         (1<<23)
 #define GTUNE_QUIC_SOCK_PER_CONN (1<<24)
 #define GTUNE_NO_QUIC            (1<<25)
+#define GTUNE_NO_FAST_FWD        (1<<26)
 
 /* SSL server verify mode */
 enum {
index 3f4c877e9ab54768270c43c5ba4de606469db8d3..542ddd0d1805e69b8eb87f170b77f37c78fdb73c 100644 (file)
@@ -36,7 +36,8 @@ static const char *common_kw_list[] = {
        "tune.idletimer", "tune.rcvbuf.client", "tune.rcvbuf.server",
        "tune.sndbuf.client", "tune.sndbuf.server", "tune.pipesize",
        "tune.http.cookielen", "tune.http.logurilen", "tune.http.maxhdr",
-       "tune.comp.maxlevel", "tune.pattern.cache-size", "uid", "gid",
+       "tune.comp.maxlevel", "tune.pattern.cache-size",
+       "tune.fast-forward", "uid", "gid",
        "external-check", "user", "group", "nbproc", "maxconn",
        "ssl-server-verify", "maxconnrate", "maxsessrate", "maxsslrate",
        "maxcomprate", "maxpipes", "maxzlibmem", "maxcompcpuusage", "ulimit-n",
@@ -492,6 +493,34 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
        }
+       else if (strcmp(args[0], "tune.fast-forward") == 0) {
+               if (!experimental_directives_allowed) {
+                       ha_alert("parsing [%s:%d] : '%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'",
+                                file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
+
+               if (alertif_too_many_args(1, file, linenum, args, &err_code))
+                       goto out;
+               if (*(args[1]) == 0) {
+                       ha_alert("parsing [%s:%d] : '%s' expects either 'on' or 'off' as argument.",
+                                file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               if (strcmp(args[1], "on") == 0)
+                       global.tune.options &= ~GTUNE_NO_FAST_FWD;
+               else if (strcmp(args[1], "off") == 0)
+                       global.tune.options |= GTUNE_NO_FAST_FWD;
+               else {
+                       ha_alert("parsing [%s:%d] : '%s' expects either 'on' or 'off' but got '%s'.",
+                                file, linenum, args[0], args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+       }
        else if (strcmp(args[0], "cluster-secret") == 0) {
                if (alertif_too_many_args(1, file, linenum, args, &err_code))
                        goto out;
index a4092a7abba459f33106a4b4c0ab7acde9c8df6d..e5b85670693ccf82ab72efec8eb18cb59fd02644 100644 (file)
@@ -941,7 +941,7 @@ int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
        }
        else {
                c_adv(req, htx->data - co_data(req));
-               if (msg->flags & HTTP_MSGF_XFER_LEN)
+               if (!(global.tune.options & GTUNE_NO_FAST_FWD) && (msg->flags & HTTP_MSGF_XFER_LEN))
                        channel_htx_forward_forever(req, htx);
        }
 
@@ -2044,7 +2044,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
        }
        else {
                c_adv(res, htx->data - co_data(res));
-               if (msg->flags & HTTP_MSGF_XFER_LEN)
+               if (!(global.tune.options & GTUNE_NO_FAST_FWD) && (msg->flags & HTTP_MSGF_XFER_LEN))
                        channel_htx_forward_forever(res, htx);
        }
 
index b01f44d285d2bf4e3a1aaa1792bc1d9581424355..e6beded8799e6cb37424c335ab5653e7381bc3b5 100644 (file)
@@ -2258,7 +2258,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                         * to the consumer.
                         */
                        co_set_data(req, htx->data);
-                       if (!(req->flags & (CF_SHUTR|CF_SHUTW_NOW)))
+                       if (!(global.tune.options & GTUNE_NO_FAST_FWD) && !(req->flags & (CF_SHUTR|CF_SHUTW_NOW)))
                                channel_htx_forward_forever(req, htx);
                }
                else {
@@ -2266,7 +2266,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                         * to the consumer (which might possibly not be connected yet).
                         */
                        c_adv(req, ci_data(req));
-                       if (!(req->flags & (CF_SHUTR|CF_SHUTW_NOW)))
+                       if (!(global.tune.options & GTUNE_NO_FAST_FWD) && !(req->flags & (CF_SHUTR|CF_SHUTW_NOW)))
                                channel_forward_forever(req);
                }
        }
@@ -2429,7 +2429,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                         * to the consumer.
                         */
                        co_set_data(res, htx->data);
-                       if (!(res->flags & (CF_SHUTR|CF_SHUTW_NOW)))
+                       if (!(global.tune.options & GTUNE_NO_FAST_FWD) && !(res->flags & (CF_SHUTR|CF_SHUTW_NOW)))
                                channel_htx_forward_forever(res, htx);
                }
                else {
@@ -2437,7 +2437,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
                         * to the consumer.
                         */
                        c_adv(res, ci_data(res));
-                       if (!(res->flags & (CF_SHUTR|CF_SHUTW_NOW)))
+                       if (!(global.tune.options & GTUNE_NO_FAST_FWD) && !(res->flags & (CF_SHUTR|CF_SHUTW_NOW)))
                                channel_forward_forever(res);
                }