MINOR: mux-h2/trace: register a new trace source with its events

For now the traces are not used. Supported events are categorized by
where the activity comes from (h2c, h2s, stream, etc), a direction
(send/recv/wake), and a list of possibilities for each of them (frame
types, errors, shut, ...). This results in ~50 different events that
try to cover a lot of possibilities when it's needed to filter on
something specific. Special events like protocol error are handled.
A few aggregate events like "rx_frame" or "tx_frame" are planed to
cover all frame types at once by being placed all the time with any
of the other ones.

We also state that the first argument is always the connection. This way
the trace subsystem will be able to safely retrieve some useful info, and
we'll still be able to get the h2c from there (conn->ctx) in a pretty
print function. The second argument will always be an h2s, and in order
to propose it for tracking, we add its description. We also define 4
verbosity levels, which seems more than enough.
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 229f5ba..6681034 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -22,6 +22,7 @@
 #include <common/net_helper.h>
 #include <proto/connection.h>
 #include <proto/http_htx.h>
+#include <proto/trace.h>
 #include <proto/session.h>
 #include <proto/stream.h>
 #include <proto/stream_interface.h>
@@ -221,6 +222,151 @@
 	uint8_t ff;         /* frame flags */
 };
 
+/* trace source and events */
+
+/* The event representation is split like this :
+ *   strm  - application layer
+ *   h2s   - internal H2 stream
+ *   h2c   - internal H2 connection
+ *   conn  - external connection
+ *
+ */
+static const struct trace_event h2_trace_events[] = {
+#define           H2_EV_H2C_NEW       (1ULL <<  0)
+	{ .mask = H2_EV_H2C_NEW,      .name = "H2C_NEW",     .desc = "new H2 connection" },
+#define           H2_EV_H2C_RECV      (1ULL <<  1)
+	{ .mask = H2_EV_H2C_RECV,     .name = "H2C_RECV",    .desc = "Rx on H2 connection" },
+#define           H2_EV_H2C_SEND      (1ULL <<  2)
+	{ .mask = H2_EV_H2C_SEND,     .name = "H2C_SEND",    .desc = "Tx on H2 connection" },
+#define           H2_EV_H2C_FCTL      (1ULL <<  3)
+	{ .mask = H2_EV_H2C_FCTL,     .name = "H2C_FCTL",    .desc = "H2 connection flow-controlled" },
+#define           H2_EV_H2C_BLK       (1ULL <<  4)
+	{ .mask = H2_EV_H2C_BLK,      .name = "H2C_BLK",     .desc = "H2 connection blocked" },
+#define           H2_EV_H2C_WAKE      (1ULL <<  5)
+	{ .mask = H2_EV_H2C_WAKE,     .name = "H2C_WAKE",    .desc = "H2 connection woken up" },
+#define           H2_EV_H2C_END       (1ULL <<  6)
+	{ .mask = H2_EV_H2C_END,      .name = "H2C_END",     .desc = "H2 connection terminated" },
+#define           H2_EV_H2C_ERR       (1ULL <<  7)
+	{ .mask = H2_EV_H2C_ERR,      .name = "H2C_ERR",     .desc = "error on H2 connection" },
+#define           H2_EV_RX_FHDR       (1ULL <<  8)
+	{ .mask = H2_EV_RX_FHDR,      .name = "RX_FHDR",     .desc = "H2 frame header received" },
+#define           H2_EV_RX_FRAME      (1ULL <<  9)
+	{ .mask = H2_EV_RX_FRAME,     .name = "RX_FRAME",    .desc = "receipt of any H2 frame" },
+#define           H2_EV_RX_EOI        (1ULL << 10)
+	{ .mask = H2_EV_RX_EOI,       .name = "RX_EOI",      .desc = "receipt of end of H2 input (ES or RST)" },
+#define           H2_EV_RX_PREFACE    (1ULL << 11)
+	{ .mask = H2_EV_RX_PREFACE,   .name = "RX_PREFACE",  .desc = "receipt of H2 preface" },
+#define           H2_EV_RX_DATA       (1ULL << 12)
+	{ .mask = H2_EV_RX_DATA,      .name = "RX_DATA",     .desc = "receipt of H2 DATA frame" },
+#define           H2_EV_RX_HDR        (1ULL << 13)
+	{ .mask = H2_EV_RX_HDR,       .name = "RX_HDR",      .desc = "receipt of H2 HEADERS frame" },
+#define           H2_EV_RX_PRIO       (1ULL << 14)
+	{ .mask = H2_EV_RX_PRIO,      .name = "RX_PRIO",     .desc = "receipt of H2 PRIORITY frame" },
+#define           H2_EV_RX_RST        (1ULL << 15)
+	{ .mask = H2_EV_RX_RST,       .name = "RX_RST",      .desc = "receipt of H2 RST_STREAM frame" },
+#define           H2_EV_RX_SETTINGS   (1ULL << 16)
+	{ .mask = H2_EV_RX_SETTINGS,  .name = "RX_SETTINGS", .desc = "receipt of H2 SETTINGS frame" },
+#define           H2_EV_RX_PUSH       (1ULL << 17)
+	{ .mask = H2_EV_RX_PUSH,      .name = "RX_PUSH",     .desc = "receipt of H2 PUSH_PROMISE frame" },
+#define           H2_EV_RX_PING       (1ULL << 18)
+	{ .mask = H2_EV_RX_PING,      .name = "RX_PING",     .desc = "receipt of H2 PING frame" },
+#define           H2_EV_RX_GOAWAY     (1ULL << 19)
+	{ .mask = H2_EV_RX_GOAWAY,    .name = "RX_GOAWAY",   .desc = "receipt of H2 GOAWAY frame" },
+#define           H2_EV_RX_WU         (1ULL << 20)
+	{ .mask = H2_EV_RX_WU,        .name = "RX_WU",       .desc = "receipt of H2 WINDOW_UPDATE frame" },
+#define           H2_EV_RX_CONT       (1ULL << 21)
+	{ .mask = H2_EV_RX_CONT,      .name = "RX_CONT",     .desc = "receipt of H2 CONTINUATION frame" },
+#define           H2_EV_TX_FRAME      (1ULL << 22)
+	{ .mask = H2_EV_TX_FRAME,     .name = "TX_FRAME",    .desc = "transmission of any H2 frame" },
+#define           H2_EV_TX_EOI        (1ULL << 23)
+	{ .mask = H2_EV_TX_EOI,       .name = "TX_EOI",      .desc = "transmission of H2 end of input (ES or RST)" },
+#define           H2_EV_TX_PREFACE    (1ULL << 24)
+	{ .mask = H2_EV_TX_PREFACE,   .name = "TX_PREFACE",  .desc = "transmission of H2 preface" },
+#define           H2_EV_TX_DATA       (1ULL << 25)
+	{ .mask = H2_EV_TX_DATA,      .name = "TX_DATA",     .desc = "transmission of H2 DATA frame" },
+#define           H2_EV_TX_HDR        (1ULL << 26)
+	{ .mask = H2_EV_TX_HDR,       .name = "TX_HDR",      .desc = "transmission of H2 HEADERS frame" },
+#define           H2_EV_TX_PRIO       (1ULL << 27)
+	{ .mask = H2_EV_TX_PRIO,      .name = "TX_PRIO",     .desc = "transmission of H2 PRIORITY frame" },
+#define           H2_EV_TX_RST        (1ULL << 28)
+	{ .mask = H2_EV_TX_RST,       .name = "TX_RST",      .desc = "transmission of H2 RST_STREAM frame" },
+#define           H2_EV_TX_SETTINGS   (1ULL << 29)
+	{ .mask = H2_EV_TX_SETTINGS,  .name = "TX_SETTINGS", .desc = "transmission of H2 SETTINGS frame" },
+#define           H2_EV_TX_PUSH       (1ULL << 30)
+	{ .mask = H2_EV_TX_PUSH,      .name = "TX_PUSH",     .desc = "transmission of H2 PUSH_PROMISE frame" },
+#define           H2_EV_TX_PING       (1ULL << 31)
+	{ .mask = H2_EV_TX_PING,      .name = "TX_PING",     .desc = "transmission of H2 PING frame" },
+#define           H2_EV_TX_GOAWAY     (1ULL << 32)
+	{ .mask = H2_EV_TX_GOAWAY,    .name = "TX_GOAWAY",   .desc = "transmission of H2 GOAWAY frame" },
+#define           H2_EV_TX_WU         (1ULL << 33)
+	{ .mask = H2_EV_TX_WU,        .name = "TX_WU",       .desc = "transmission of H2 WINDOW_UPDATE frame" },
+#define           H2_EV_TX_CONT       (1ULL << 34)
+	{ .mask = H2_EV_TX_CONT,      .name = "TX_CONT",     .desc = "transmission of H2 CONTINUATION frame" },
+#define           H2_EV_H2S_NEW       (1ULL << 35)
+	{ .mask = H2_EV_H2S_NEW,      .name = "H2S_NEW",     .desc = "new H2 stream" },
+#define           H2_EV_H2S_RECV      (1ULL << 36)
+	{ .mask = H2_EV_H2S_RECV,     .name = "H2S_RECV",    .desc = "Rx for H2 stream" },
+#define           H2_EV_H2S_SEND      (1ULL << 37)
+	{ .mask = H2_EV_H2S_SEND,     .name = "H2S_SEND",    .desc = "Tx for H2 stream" },
+#define           H2_EV_H2S_FCTL      (1ULL << 38)
+	{ .mask = H2_EV_H2S_FCTL,     .name = "H2S_FCTL",    .desc = "H2 stream flow-controlled" },
+#define           H2_EV_H2S_BLK       (1ULL << 39)
+	{ .mask = H2_EV_H2S_BLK,      .name = "H2S_BLK",     .desc = "H2 stream blocked" },
+#define           H2_EV_H2S_WAKE      (1ULL << 40)
+	{ .mask = H2_EV_H2S_WAKE,     .name = "H2S_WAKE",    .desc = "H2 stream woken up" },
+#define           H2_EV_H2S_END       (1ULL << 41)
+	{ .mask = H2_EV_H2S_END,      .name = "H2S_END",     .desc = "H2 stream terminated" },
+#define           H2_EV_H2S_ERR       (1ULL << 42)
+	{ .mask = H2_EV_H2S_ERR,      .name = "H2S_ERR",     .desc = "error on H2 stream" },
+#define           H2_EV_STRM_NEW      (1ULL << 43)
+	{ .mask = H2_EV_STRM_NEW,     .name = "STRM_NEW",    .desc = "app-layer stream creation" },
+#define           H2_EV_STRM_RECV     (1ULL << 44)
+	{ .mask = H2_EV_STRM_RECV,    .name = "STRM_RECV",   .desc = "receiving data for stream" },
+#define           H2_EV_STRM_SEND     (1ULL << 45)
+	{ .mask = H2_EV_STRM_SEND,    .name = "STRM_SEND",   .desc = "sending data for stream" },
+#define           H2_EV_STRM_FULL     (1ULL << 46)
+	{ .mask = H2_EV_STRM_FULL,    .name = "STRM_FULL",   .desc = "stream buffer full" },
+#define           H2_EV_STRM_WAKE     (1ULL << 47)
+	{ .mask = H2_EV_STRM_WAKE,    .name = "STRM_WAKE",   .desc = "stream woken up" },
+#define           H2_EV_STRM_SHUT     (1ULL << 48)
+	{ .mask = H2_EV_STRM_SHUT,    .name = "STRM_SHUT",   .desc = "stream shutdown" },
+#define           H2_EV_STRM_END      (1ULL << 49)
+	{ .mask = H2_EV_STRM_END,     .name = "STRM_END",    .desc = "detaching app-layer stream" },
+#define           H2_EV_STRM_ERR      (1ULL << 50)
+	{ .mask = H2_EV_STRM_ERR,     .name = "STRM_ERR",    .desc = "stream error" },
+#define           H2_EV_PROTO_ERR     (1ULL << 51)
+	{ .mask = H2_EV_PROTO_ERR,    .name = "PROTO_ERR",   .desc = "protocol error" },
+	{ }
+};
+
+static const struct name_desc h2_trace_lockon_args[4] = {
+	/* arg1 */ { /* already used by the connection */ },
+	/* arg2 */ { .name="h2s", .desc="H2 stream" },
+	/* arg3 */ { },
+	/* arg4 */ { }
+};
+
+static const struct name_desc h2_trace_decoding[] = {
+	{ .name="minimal",  .desc="report only h2c/h2s state and flags, no real decoding" },
+	{ .name="simple",   .desc="add request/response status line or frame info when available" },
+	{ .name="advanced", .desc="add header fields or frame decoding when available" },
+	{ .name="complete", .desc="add full data dump when available" },
+	{ /* end */ }
+};
+
+static struct trace_source trace_h2 = {
+	.name = IST("h2"),
+	.desc = "HTTP/2 multiplexer",
+	.arg_def = TRC_ARG1_CONN,  // TRACE()'s first argument is always a connection
+	.known_events = h2_trace_events,
+	.lockon_args = h2_trace_lockon_args,
+	.decoding = h2_trace_decoding,
+	.report_events = ~0,  // report everything by default
+};
+
+#define TRACE_SOURCE &trace_h2
+INITCALL1(STG_REGISTER, trace_register_source, TRACE_SOURCE);
+
 /* the h2c connection pool */
 DECLARE_STATIC_POOL(pool_head_h2c, "h2c", sizeof(struct h2c));