summaryrefslogtreecommitdiffstats
path: root/src/qmux_trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmux_trace.c')
-rw-r--r--src/qmux_trace.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/qmux_trace.c b/src/qmux_trace.c
new file mode 100644
index 0000000..b213ed4
--- /dev/null
+++ b/src/qmux_trace.c
@@ -0,0 +1,114 @@
+#include <haproxy/qmux_trace.h>
+
+#include <import/ist.h>
+#include <haproxy/api.h>
+#include <haproxy/connection.h>
+#include <haproxy/chunk.h>
+#include <haproxy/mux_quic.h>
+#include <haproxy/quic_frame-t.h>
+
+/* trace source and events */
+static void qmux_trace(enum trace_level level, uint64_t mask,
+ const struct trace_source *src,
+ const struct ist where, const struct ist func,
+ const void *a1, const void *a2, const void *a3, const void *a4);
+
+static const struct name_desc qmux_trace_lockon_args[4] = {
+ /* arg1 */ { /* already used by the connection */ },
+ /* arg2 */ { .name="qcs", .desc="QUIC stream" },
+ /* arg3 */ { },
+ /* arg4 */ { }
+};
+
+static const struct name_desc qmux_trace_decoding[] = {
+#define QMUX_VERB_CLEAN 1
+ { .name="clean", .desc="only user-friendly stuff, generally suitable for level \"user\"" },
+#define QMUX_VERB_MINIMAL 2
+ { .name="minimal", .desc="report only qcc/qcs state and flags, no real decoding" },
+ { /* end */ }
+};
+
+struct trace_source trace_qmux = {
+ .name = IST("qmux"),
+ .desc = "QUIC multiplexer",
+ .arg_def = TRC_ARG1_CONN, /* TRACE()'s first argument is always a connection */
+ .default_cb = qmux_trace,
+ .known_events = qmux_trace_events,
+ .lockon_args = qmux_trace_lockon_args,
+ .decoding = qmux_trace_decoding,
+ .report_events = ~0, /* report everything by default */
+};
+
+
+static void qmux_trace_frm(const struct quic_frame *frm)
+{
+ switch (frm->type) {
+ case QUIC_FT_MAX_STREAMS_BIDI:
+ chunk_appendf(&trace_buf, " max_streams=%llu",
+ (ullong)frm->max_streams_bidi.max_streams);
+ break;
+
+ case QUIC_FT_MAX_STREAMS_UNI:
+ chunk_appendf(&trace_buf, " max_streams=%llu",
+ (ullong)frm->max_streams_uni.max_streams);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* quic-mux trace handler */
+static void qmux_trace(enum trace_level level, uint64_t mask,
+ const struct trace_source *src,
+ const struct ist where, const struct ist func,
+ const void *a1, const void *a2, const void *a3, const void *a4)
+{
+ const struct connection *conn = a1;
+ const struct qcc *qcc = conn ? conn->ctx : NULL;
+ const struct qcs *qcs = a2;
+
+ if (!qcc)
+ return;
+
+ if (src->verbosity > QMUX_VERB_CLEAN) {
+ chunk_appendf(&trace_buf, " : qcc=%p(F)", qcc);
+ if (qcc->conn->handle.qc)
+ chunk_appendf(&trace_buf, " qc=%p", qcc->conn->handle.qc);
+
+ chunk_appendf(&trace_buf, " md=%llu/%llu/%llu",
+ (ullong)qcc->rfctl.md, (ullong)qcc->tx.offsets, (ullong)qcc->tx.sent_offsets);
+
+ if (qcs) {
+ chunk_appendf(&trace_buf, " qcs=%p .id=%llu .st=%s",
+ qcs, (ullong)qcs->id,
+ qcs_st_to_str(qcs->st));
+ chunk_appendf(&trace_buf, " msd=%llu/%llu/%llu",
+ (ullong)qcs->tx.msd, (ullong)qcs->tx.offset, (ullong)qcs->tx.sent_offset);
+ }
+
+ if (mask & QMUX_EV_QCC_NQCS) {
+ const uint64_t *id = a3;
+ chunk_appendf(&trace_buf, " id=%llu", (ullong)*id);
+ }
+
+ if (mask & QMUX_EV_SEND_FRM)
+ qmux_trace_frm(a3);
+
+ if (mask & QMUX_EV_QCS_XFER_DATA) {
+ const struct qcs_xfer_data_trace_arg *arg = a3;
+ chunk_appendf(&trace_buf, " prep=%lu xfer=%d",
+ (ulong)arg->prep, arg->xfer);
+ }
+
+ if (mask & QMUX_EV_QCS_BUILD_STRM) {
+ const struct qcs_build_stream_trace_arg *arg = a3;
+ chunk_appendf(&trace_buf, " len=%lu fin=%d offset=%llu",
+ (ulong)arg->len, arg->fin, (ullong)arg->offset);
+ }
+ }
+}
+
+
+/* register qmux traces */
+INITCALL1(STG_REGISTER, trace_register_source, TRACE_SOURCE);