]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: applet: Add a flag to state an applet is using zero-copy forwarding
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 12 Feb 2024 21:13:23 +0000 (22:13 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 14 Feb 2024 13:22:36 +0000 (14:22 +0100)
An issue was introduced when zero-copy forwarding was added to the stats and
cache applets. There is no test to be sure the upper layer is ready to use
the zero-copy forwarding. So these applets refuse to deliver the response
into the applet's output buffer if the zero-copy forwarding is supported by
the opposite endpoint. It is especially an issue when a filter, like the
compression, is in-use on the response channel.

Because of this bug, the response is not delivered and the applet is woken
up in loop to produce data.

To fix the issue, an appctx flag was added, APPCTX_FL_FASTFWD, to know when
the zero-copy forwarding is in-use. We rely on this flag to not fill the
outbuf in the applet's I/O handler.

No backport needed.

include/haproxy/applet-t.h
src/applet.c
src/cache.c
src/stats.c

index 8360c85576ce4ddc9133250797169dea6db5eecd..b730233b0a7b2caf6e6a9cc5572b642542a786c0 100644 (file)
@@ -47,6 +47,7 @@
 #define APPCTX_FL_SHUTDOWN       0x00000100  /* applet was shut down (->release() called if any). No more data exchange with SCs */
 #define APPCTX_FL_WANT_DIE       0x00000200  /* applet was running and requested to die */
 #define APPCTX_FL_INOUT_BUFS     0x00000400  /* applet uses its own buffers */
+#define APPCTX_FL_FASTFWD        0x00000800  /* zero-copy forwarding is in-use, don't fill the outbuf */
 
 struct appctx;
 struct proxy;
index 0147590416aa5330277caba2406005092e028954..1d7306a1398cd8de8e0345f8932a22fddc0dd6d0 100644 (file)
@@ -537,6 +537,9 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
                goto end;
        }
 
+       if (flags & CO_RFL_BUF_FLUSH)
+               applet_fl_set(appctx, APPCTX_FL_FASTFWD);
+
        ret = appctx->applet->rcv_buf(appctx, buf, count, flags);
        if (ret)
                applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
@@ -648,6 +651,8 @@ int appctx_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags)
 
        TRACE_ENTER(APPLET_EV_RECV, appctx);
 
+       applet_fl_set(appctx, APPCTX_FL_FASTFWD);
+
        /* TODO: outbuf must be empty. Find a better way to handle that but for now just return -1 */
        if (b_data(&appctx->outbuf)) {
                TRACE_STATE("Output buffer not empty, cannot fast-forward data", APPLET_EV_RECV, appctx);
@@ -670,6 +675,7 @@ int appctx_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags)
        len = se_nego_ff(sdo, &BUF_NULL, count, nego_flags);
        if (sdo->iobuf.flags & IOBUF_FL_NO_FF) {
                sc_ep_clr(sc, SE_FL_MAY_FASTFWD);
+               applet_fl_clr(appctx, APPCTX_FL_FASTFWD);
                TRACE_DEVEL("Fast-forwarding not supported by opposite endpoint, disable it", APPLET_EV_RECV, appctx);
                goto end;
        }
index d4757ab31ee9bb87df303338de0b4af448bc65ee..0cbc96a78bdfc2af03d1d434581b53ebfd0de8a3 100644 (file)
@@ -1757,6 +1757,7 @@ static size_t http_cache_fastfwd(struct appctx *appctx, struct buffer *buf, size
 
        if (!appctx->to_forward) {
                se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD);
+               applet_fl_clr(appctx, APPCTX_FL_FASTFWD);
                if (ctx->sent == first->len - sizeof(*cache_ptr)) {
                        applet_set_eoi(appctx);
                        applet_set_eos(appctx);
@@ -1779,7 +1780,7 @@ static void http_cache_io_handler(struct appctx *appctx)
        if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
                goto exit;
 
-       if (se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD))
+       if (applet_fl_test(appctx, APPCTX_FL_FASTFWD) && se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD))
                goto exit;
 
        if (!appctx_get_buf(appctx, &appctx->outbuf)) {
@@ -1853,6 +1854,7 @@ static void http_cache_io_handler(struct appctx *appctx)
                res_htx->flags |= HTX_FL_EOM;
                applet_set_eoi(appctx);
                se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD);
+               applet_fl_clr(appctx, APPCTX_FL_FASTFWD);
                appctx->st0 = HTX_CACHE_END;
        }
 
index 0072c2e1655b290f44ee1a7e1ceaf7974b23fd3b..bf826afe3203cde4cdb0ba7f4bfb9f40d294d65a 100644 (file)
@@ -4471,6 +4471,7 @@ static size_t http_stats_fastfwd(struct appctx *appctx, struct buffer *buf, size
        ret = b_data(buf);
        if (stats_dump_stat_to_buffer(sc, buf, NULL)) {
                se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD);
+               applet_fl_clr(appctx, APPCTX_FL_FASTFWD);
                appctx->st0 = STAT_HTTP_DONE;
        }
 
@@ -4495,7 +4496,7 @@ static void http_stats_io_handler(struct appctx *appctx)
        if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
                goto out;
 
-       if (se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD))
+       if (applet_fl_test(appctx, APPCTX_FL_FASTFWD) && se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD))
                goto out;
 
        if (!appctx_get_buf(appctx, &appctx->outbuf)) {
@@ -4560,6 +4561,7 @@ static void http_stats_io_handler(struct appctx *appctx)
                res_htx->flags |= HTX_FL_EOM;
                applet_set_eoi(appctx);
                se_fl_clr(appctx->sedesc, SE_FL_MAY_FASTFWD);
+               applet_fl_clr(appctx, APPCTX_FL_FASTFWD);
                appctx->st0 = STAT_HTTP_END;
        }