]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: stconn/muxes: Add an abort reason for SE shutdowns on muxes
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 29 Apr 2024 06:12:07 +0000 (08:12 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 6 May 2024 20:00:00 +0000 (22:00 +0200)
A reason is now passed as parameter to muxes shutdowns to pass additional
info about the abort, if any. No info means no abort or only generic one.

For now, the reason is composed of 2 32-bits integer. The first on represents
the abort code and the other one represents the info about the code (for
instance the source). The code should be interpreted according to the associated
info.

One info is the source, encoding on 5 bits. Other bits are reserverd for now.
For now, the muxes are the only supported source. But we can imagine to extend
it to applets, streams, health-checks...

The current design is quite simple and will most probably evolved.. But the
idea is to let the opposite side forward some errors and let's a mux know
why its stream was aborted. At first glance, a abort reason must only be
evaluated if SE_SHW_SILENT flag is set.

The main goal at short term, is to forward some H2 RST_STREAM codes because
it is mandatory for gRPC applications, mainly to forward gRPC cancellation
from an H2 client to an H2 server. But we can imagine to alter this reason
at the applicative level to enrich it. It would also be used to report more
accurate errors in logs.

include/haproxy/connection-t.h
include/haproxy/stconn-t.h
src/mux_fcgi.c
src/mux_h1.c
src/mux_h2.c
src/mux_pt.c
src/mux_quic.c
src/stconn.c

index 342abba5d4bcae188c9f08025426b7de34b96514..aad813e0cb29ab0d52ecd590b2c340277fe644b8 100644 (file)
@@ -411,7 +411,7 @@ struct mux_ops {
        size_t (*done_fastfwd)(struct stconn *sc); /* Callback to terminate fast data forwarding */
        int (*fastfwd)(struct stconn *sc, unsigned int count, unsigned int flags); /* Callback to init fast data forwarding */
        int (*resume_fastfwd)(struct stconn *sc, unsigned int flags); /* Callback to resume fast data forwarding */
-       void (*shut)(struct stconn *sc, enum se_shut_mode);     /* shutdown function */
+       void (*shut)(struct stconn *sc, enum se_shut_mode, struct se_abort_info *reason); /* shutdown function */
 
        int (*attach)(struct connection *conn, struct sedesc *, struct session *sess); /* attach a stconn to an outgoing connection */
        struct stconn *(*get_first_sc)(const struct connection *); /* retrieves any valid stconn from this connection */
index 50645d0acaf4b1af948f88e3906227f45dd780c0..8f0460d3378691ff9c00d9e4bb6f8ad8b94f9cf8 100644 (file)
@@ -266,6 +266,24 @@ enum sc_state_bit {
 
 struct stconn;
 
+/* represent the abort code, enriched with contextual info:
+ *  - First 5 bits are used for the source (31 possible sources)
+ *  - other bits are reserved for now
+ */
+#define SE_ABRT_SRC_SHIFT 0
+#define SE_ABRT_SRC_MASK  0x0000001f
+
+#define SE_ABRT_SRC_MUX_PT    0x01 /* Code set by the PT mux */
+#define SE_ABRT_SRC_MUX_H1    0x02 /* Code set bu the H1 mux */
+#define SE_ABRT_SRC_MUX_H2    0x03 /* Code set bu the H2 mux */
+#define SE_ABRT_SRC_MUX_QUIC  0x04 /* Code set bu the QUIC/H3 mux */
+#define SE_ABRT_SRC_MUX_FCGI  0x05 /* Code set bu the FCGI mux */
+
+struct se_abort_info {
+       uint32_t info;
+       uint64_t code;
+};
+
 /* A Stream Endpoint Descriptor (sedesc) is the link between the stream
  * connector (ex. stconn) and the Stream Endpoint (mux or appctx).
  * It always exists for either of them, and binds them together. It also
@@ -296,6 +314,7 @@ struct sedesc {
        struct stconn *sc;         /* the stream connector we're attached to, or NULL */
        struct iobuf iobuf;        /* contains data forwarded by the other side and that must be sent by the stream endpoint */
        unsigned int flags;        /* SE_FL_* */
+       struct se_abort_info abort_info; /* Info about abort, as reported by the endpoint and eventually enriched by the app level */
        unsigned int lra;          /* the last read activity */
        unsigned int fsb;          /* the first send blocked */
        /* 4 bytes hole here */
index b914eadfeee91a44b44b4dab1b6f83026a51a4de..a611c0a7e70cd1f8be2b07878815155bb96d3c1e 100644 (file)
@@ -3791,7 +3791,7 @@ struct task *fcgi_deferred_shut(struct task *t, void *ctx, unsigned int state)
        return NULL;
 }
 
-static void fcgi_shut(struct stconn *sc, enum se_shut_mode mode)
+static void fcgi_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason)
 {
        struct fcgi_strm *fstrm = __sc_mux_strm(sc);
 
index 397f75a1293478981368f12a10f81b80b7403d95..39e23956c912bb4669a3c7b42f53d7f6cbb8efa8 100644 (file)
@@ -4291,7 +4291,7 @@ static void h1_detach(struct sedesc *sd)
        TRACE_LEAVE(H1_EV_STRM_END);
 }
 
-static void h1_shut(struct stconn *sc, enum se_shut_mode mode)
+static void h1_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason)
 {
        struct h1s *h1s = __sc_mux_strm(sc);
        struct h1c *h1c;
index a3ce0eb891f6dfffc9c9642bc9b5c70728d17bb5..fbf03a6e736644bfe99446f7de0c6b65aae35d32 100644 (file)
@@ -5079,7 +5079,7 @@ struct task *h2_deferred_shut(struct task *t, void *ctx, unsigned int state)
        return t;
 }
 
-static void h2_shut(struct stconn *sc, enum se_shut_mode mode)
+static void h2_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason)
 {
        struct h2s *h2s = __sc_mux_strm(sc);
 
index 7aa97d79328aca5a5e4fc7f380dd2552b8794adc..dc9702eb0b6d63cf14dc98c56c9e6fa7b2d38782 100644 (file)
@@ -462,7 +462,7 @@ static int mux_pt_avail_streams(struct connection *conn)
        return 1 - mux_pt_used_streams(conn);
 }
 
-static void mux_pt_shut(struct stconn *sc, enum se_shut_mode mode)
+static void mux_pt_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason)
 {
        struct connection *conn = __sc_conn(sc);
        struct mux_pt_ctx *ctx = conn->ctx;
index 883ef01bb2661edeec5b49ebbf8e7434bcd24065..d7474ffb2bfcb0b3dfbaa50af89ff02d95236936 100644 (file)
@@ -3095,7 +3095,7 @@ static int qmux_wake(struct connection *conn)
        return 1;
 }
 
-static void qmux_strm_shut(struct stconn *sc, enum se_shut_mode mode)
+static void qmux_strm_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_info *reason)
 {
        struct qcs *qcs = __sc_mux_strm(sc);
        struct qcc *qcc = qcs->qcc;
index f6d20ea4f65cc98513885c188aaba1ebe408686d..53888efb4a8e5989f66528dfcb7003ad83909d9b 100644 (file)
@@ -100,6 +100,9 @@ void sedesc_init(struct sedesc *sedesc)
        sedesc->xref.peer = NULL;
        se_fl_setall(sedesc, SE_FL_NONE);
 
+       sedesc->abort_info.info = 0;
+       sedesc->abort_info.code = 0;
+
        sedesc->iobuf.pipe = NULL;
        sedesc->iobuf.buf = NULL;
        sedesc->iobuf.offset = sedesc->iobuf.data = 0;
@@ -150,8 +153,20 @@ void se_shutdown(struct sedesc *sedesc, enum se_shut_mode mode)
                        flags |= (mode & SE_SHR_DRAIN) ? SE_FL_SHRD : SE_FL_SHRR;
 
                if (flags) {
-                       if (mux && mux->shut)
-                               mux->shut(sedesc->sc, mode);
+                       if (mux && mux->shut) {
+                               struct se_abort_info *reason = NULL;
+                               struct xref *peer = xref_get_peer_and_lock(&sedesc->xref);
+
+                               if (peer) {
+                                       struct sedesc *sdo = container_of(peer, struct sedesc, xref);
+
+                                       reason = &sdo->abort_info;
+                                       xref_unlock(&sedesc->xref, peer);
+                               }
+
+                               mux->shut(sedesc->sc, mode, reason);
+
+                       }
                        se_fl_set(sedesc, flags);
                }
        }