]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-quic: define a flow control related type
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 3 Jan 2024 15:14:52 +0000 (16:14 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 31 Jan 2024 15:28:54 +0000 (16:28 +0100)
Create a new module dedicated to flow control handling. It will be used
to implement earlier flow control update on snd_buf stream callback.

For the moment, only Tx part is implemented (i.e. limit set by the peer
that haproxy must respect for sending). A type quic_fctl is defined to
count emitted data bytes. Two offsets are used : a real one and a soft
one. The difference is that soft offset can be incremented beyond limit
unless it is already in excess.

Soft offset will be used for HTX to H3 parsing. As size of generated H3
is unknown before parsing, it allows to surpass the limit one time. Real
offset will be used during STREAM frame generation : this time the limit
must not be exceeded to prevent protocol violation.

Makefile
include/haproxy/quic_fctl-t.h [new file with mode: 0644]
include/haproxy/quic_fctl.h [new file with mode: 0644]
src/quic_fctl.c [new file with mode: 0644]

index df637cf68d4dd07f5b34e75383abf280fb8f867d..26993ee1c6b6e177fa78e76a6514e29357d3cf44 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -621,7 +621,7 @@ OPTIONS_OBJS += src/quic_conn.o src/mux_quic.o src/h3.o src/xprt_quic.o    \
                 src/cbuf.o src/quic_cc.o src/quic_cc_nocc.o src/quic_ack.o \
                 src/quic_trace.o src/quic_cli.o src/quic_ssl.o             \
                 src/quic_rx.o src/quic_tx.o src/quic_cid.o src/quic_retry.o\
-                src/quic_retransmit.o
+                src/quic_retransmit.o src/quic_fctl.o
 endif
 
 ifneq ($(USE_QUIC_OPENSSL_COMPAT),)
diff --git a/include/haproxy/quic_fctl-t.h b/include/haproxy/quic_fctl-t.h
new file mode 100644 (file)
index 0000000..9331619
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _HAPROXY_QUIC_FCTL_T_H
+#define _HAPROXY_QUIC_FCTL_T_H
+
+#include <stdint.h>
+
+struct quic_fctl {
+       /* Offset set by peer which must not be exceeded on send. */
+       uint64_t limit;
+       /* Offset which must never exceed limit. */
+       uint64_t off_real;
+       /* Offset which can go beyond limit one time before being blocked. */
+       uint64_t off_soft;
+};
+
+#endif /* _HAPROXY_QUIC_FCTL_T_H */
diff --git a/include/haproxy/quic_fctl.h b/include/haproxy/quic_fctl.h
new file mode 100644 (file)
index 0000000..8818372
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _HAPROXY_QUIC_FCTL_H
+#define _HAPROXY_QUIC_FCTL_H
+
+#include <haproxy/quic_fctl-t.h>
+
+void qfctl_init(struct quic_fctl *fctl, uint64_t limit);
+
+int qfctl_rblocked(const struct quic_fctl *fctl);
+int qfctl_sblocked(const struct quic_fctl *fctl);
+
+int qfctl_set_max(struct quic_fctl *fctl, uint64_t val,
+                  int *unblock_soft, int *unblock_real);
+
+int qfctl_rinc(struct quic_fctl *fctl, uint64_t diff);
+int qfctl_sinc(struct quic_fctl *fctl, uint64_t diff);
+
+uint64_t qfctl_rcap(const struct quic_fctl *fctl);
+
+#endif /* _HAPROXY_QUIC_FCTL_H */
diff --git a/src/quic_fctl.c b/src/quic_fctl.c
new file mode 100644 (file)
index 0000000..b797e55
--- /dev/null
@@ -0,0 +1,96 @@
+#include <haproxy/quic_fctl.h>
+
+#include <haproxy/api.h>
+
+void qfctl_init(struct quic_fctl *fctl, uint64_t limit)
+{
+       fctl->limit = limit;
+       fctl->off_real = 0;
+       fctl->off_soft = 0;
+}
+
+/* Returns true if real limit is blocked for <fctl> flow control instance.
+ * This happens if it is equal than current max value.
+ */
+int qfctl_rblocked(const struct quic_fctl *fctl)
+{
+       /* Real limit must never be exceeded. */
+       BUG_ON(fctl->off_real > fctl->limit);
+       return fctl->off_real == fctl->limit;
+}
+
+/* Returns true if soft limit is blocked for <fctl> flow control instance.
+ * This happens if it is equal or greater than current max value.
+ */
+int qfctl_sblocked(const struct quic_fctl *fctl)
+{
+       return fctl->off_soft >= fctl->limit;
+}
+
+/* Set a new <val> maximum value for <fctl> flow control instance. If current
+ * offset is already equal or more, the new value is ignored. Additionally,
+ * <unblocked_soft> and <unblocked_real> can be used as output parameters to
+ * detect if the current update result in one or both of these offsets to be
+ * unblocked.
+ *
+ * Returns true if max is incremented else false.
+ */
+int qfctl_set_max(struct quic_fctl *fctl, uint64_t val,
+                  int *out_unblock_soft, int *out_unblock_real)
+{
+       int unblock_soft = 0, unblock_real = 0;
+       int ret = 0;
+
+       if (fctl->limit < val) {
+               if (fctl->off_soft >= fctl->limit && fctl->off_soft < val)
+                       unblock_soft = 1;
+               if (fctl->off_real == fctl->limit && fctl->off_real < val)
+                       unblock_real = 1;
+
+               fctl->limit = val;
+               ret = 1;
+       }
+
+       if (out_unblock_soft)
+               *out_unblock_soft = unblock_soft;
+       if (out_unblock_real)
+               *out_unblock_real = unblock_real;
+
+       return ret;
+}
+
+/* Increment real offset of <fctl> flow control instance by <diff>. This cannot
+ * exceed <fctl> limit.
+ *
+ * Returns true if limit is reached after increment.
+ */
+int qfctl_rinc(struct quic_fctl *fctl, uint64_t diff)
+{
+       /* Real limit must never be exceeded. */
+       BUG_ON(fctl->off_real + diff > fctl->limit);
+       fctl->off_real += diff;
+
+       return fctl->off_real == fctl->limit;
+}
+
+/* Increment soft offset of <fctl> flow control instance by <diff>. This cannot
+ * be done if <fctl> limit was already reached.
+ *
+ * Returns true if limit is reached after increment.
+ */
+int qfctl_sinc(struct quic_fctl *fctl, uint64_t diff)
+{
+       /* Soft limit must not be incremented if already in excess. */
+       BUG_ON(qfctl_sblocked(fctl));
+       fctl->off_soft += diff;
+
+       return fctl->off_soft >= fctl->limit;
+}
+
+/* Return the remaining offset before reaching <fctl> limit. */
+uint64_t qfctl_rcap(const struct quic_fctl *fctl)
+{
+       /* Real limit must never be exceeded. */
+       BUG_ON(fctl->off_real > fctl->limit);
+       return fctl->limit - fctl->off_real;
+}