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 8360c85..b730233 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 0147590..1d7306a 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 d4757ab..0cbc96a 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 0072c2e..bf826af 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;
        }