summaryrefslogtreecommitdiffstats
path: root/src/quic_cli.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/quic_cli.c249
1 files changed, 167 insertions, 82 deletions
diff --git a/src/quic_cli.c b/src/quic_cli.c
index f237a1f..f0e147c 100644
--- a/src/quic_cli.c
+++ b/src/quic_cli.c
@@ -3,18 +3,29 @@
#include <haproxy/applet-t.h>
#include <haproxy/cli.h>
#include <haproxy/list.h>
-#include <haproxy/tools.h>
+#include <haproxy/mux_quic.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_tp.h>
+#include <haproxy/tools.h>
/* incremented by each "show quic". */
unsigned int qc_epoch = 0;
enum quic_dump_format {
+ QUIC_DUMP_FMT_DEFAULT, /* value used if not explicitly specified. */
+
QUIC_DUMP_FMT_ONELINE,
- QUIC_DUMP_FMT_FULL,
+ QUIC_DUMP_FMT_CUST,
};
+#define QUIC_DUMP_FLD_TP 0x0001
+#define QUIC_DUMP_FLD_SOCK 0x0002
+#define QUIC_DUMP_FLD_PKTNS 0x0004
+#define QUIC_DUMP_FLD_CC 0x0008
+#define QUIC_DUMP_FLD_MUX 0x0010
+/* Do not forget to update FLD_MASK when adding a new field. */
+#define QUIC_DUMP_FLD_MASK 0x001f
+
/* appctx context used by "show quic" command */
struct show_quic_ctx {
unsigned int epoch;
@@ -22,10 +33,24 @@ struct show_quic_ctx {
unsigned int thr;
int flags;
enum quic_dump_format format;
+ void *ptr;
+ int fields;
};
#define QC_CLI_FL_SHOW_ALL 0x1 /* show closing/draining connections */
+/* Returns the output format for show quic. If specified explicitly use it as
+ * set. Else format depends if filtering on a single connection instance. If
+ * true, full format is preferred else oneline.
+ */
+static enum quic_dump_format cli_show_quic_format(const struct show_quic_ctx *ctx)
+{
+ if (ctx->format == QUIC_DUMP_FMT_DEFAULT)
+ return ctx->ptr ? QUIC_DUMP_FMT_CUST : QUIC_DUMP_FMT_ONELINE;
+ else
+ return ctx->format;
+}
+
static int cli_parse_show_quic(char **args, char *payload, struct appctx *appctx, void *private)
{
struct show_quic_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
@@ -37,20 +62,87 @@ static int cli_parse_show_quic(char **args, char *payload, struct appctx *appctx
ctx->epoch = _HA_ATOMIC_FETCH_ADD(&qc_epoch, 1);
ctx->thr = 0;
ctx->flags = 0;
- ctx->format = QUIC_DUMP_FMT_ONELINE;
+ ctx->format = QUIC_DUMP_FMT_DEFAULT;
+ ctx->ptr = 0;
+ ctx->fields = 0;
if (strcmp(args[argc], "oneline") == 0) {
- /* format already used as default value */
+ ctx->format = QUIC_DUMP_FMT_ONELINE;
++argc;
}
else if (strcmp(args[argc], "full") == 0) {
- ctx->format = QUIC_DUMP_FMT_FULL;
+ ctx->format = QUIC_DUMP_FMT_CUST;
+ ctx->fields = QUIC_DUMP_FLD_MASK;
++argc;
}
+ else if (*args[argc]) {
+ struct ist istarg = ist(args[argc]);
+ struct ist field = istsplit(&istarg, ',');
+
+ do {
+ if (isteq(field, ist("tp"))) {
+ ctx->fields |= QUIC_DUMP_FLD_TP;
+ }
+ else if (isteq(field, ist("sock"))) {
+ ctx->fields |= QUIC_DUMP_FLD_SOCK;
+ }
+ else if (isteq(field, ist("pktns"))) {
+ ctx->fields |= QUIC_DUMP_FLD_PKTNS;
+ }
+ else if (isteq(field, ist("cc"))) {
+ ctx->fields |= QUIC_DUMP_FLD_CC;
+ }
+ else if (isteq(field, ist("mux"))) {
+ ctx->fields |= QUIC_DUMP_FLD_MUX;
+ }
+ else {
+ /* Current argument is comma-separated so it is
+ * interpreted as a field list but an unknown
+ * field name has been specified.
+ */
+ if (istarg.len || ctx->fields) {
+ cli_err(appctx, "Invalid field.\n");
+ return 1;
+ }
+
+ break;
+ }
+
+ field = istsplit(&istarg, ',');
+ } while (field.len);
+
+ /* At least one valid field specified, select the associated
+ * format. Else parse the current argument as a filter.
+ */
+ if (ctx->fields) {
+ ctx->format = QUIC_DUMP_FMT_CUST;
+ ++argc;
+ }
+ }
+
+ if (*args[argc]) {
+ struct ist istarg = ist(args[argc]);
+
+ if (istmatchi(istarg, ist("0x"))) {
+ char *nptr;
+ ctx->ptr = (void *)strtol(args[argc], &nptr, 16);
+ if (*nptr) {
+ cli_err(appctx, "Invalid quic_conn pointer.\n");
+ return 1;
+ }
+
+ if (!ctx->fields)
+ ctx->fields = QUIC_DUMP_FLD_MASK;
- while (*args[argc]) {
- if (strcmp(args[argc], "all") == 0)
+ ++argc;
+ }
+ else if (istmatch(istarg, ist("all"))) {
ctx->flags |= QC_CLI_FL_SHOW_ALL;
+ }
+ else {
+ cli_err(appctx, "Invalid argument.\n");
+ return 1;
+ }
++argc;
}
@@ -115,10 +207,8 @@ static void dump_quic_oneline(struct show_quic_ctx *ctx, struct quic_conn *qc)
static void dump_quic_full(struct show_quic_ctx *ctx, struct quic_conn *qc)
{
struct quic_pktns *pktns;
- struct eb64_node *node;
- struct qc_stream_desc *stream;
char bufaddr[INET6_ADDRSTRLEN], bufport[6];
- int expire, i, addnl;
+ int expire, addnl;
unsigned char cid_len;
addnl = 0;
@@ -137,12 +227,14 @@ static void dump_quic_full(struct show_quic_ctx *ctx, struct quic_conn *qc)
chunk_appendf(&trash, "\n");
- chunk_appendf(&trash, " loc. TPs:");
- quic_transport_params_dump(&trash, qc, &qc->rx.params);
- chunk_appendf(&trash, "\n");
- chunk_appendf(&trash, " rem. TPs:");
- quic_transport_params_dump(&trash, qc, &qc->tx.params);
- chunk_appendf(&trash, "\n");
+ if (ctx->fields & QUIC_DUMP_FLD_TP) {
+ chunk_appendf(&trash, " loc. TPs:");
+ quic_transport_params_dump(&trash, qc, &qc->rx.params);
+ chunk_appendf(&trash, "\n");
+ chunk_appendf(&trash, " rem. TPs:");
+ quic_transport_params_dump(&trash, qc, &qc->tx.params);
+ chunk_appendf(&trash, "\n");
+ }
/* Connection state */
if (qc->flags & QUIC_FL_CONN_CLOSING)
@@ -170,44 +262,50 @@ static void dump_quic_full(struct show_quic_ctx *ctx, struct quic_conn *qc)
chunk_appendf(&trash, "\n");
/* Socket */
- chunk_appendf(&trash, " fd=%d", qc->fd);
- if (qc->local_addr.ss_family == AF_INET ||
- qc->local_addr.ss_family == AF_INET6) {
- addr_to_str(&qc->local_addr, bufaddr, sizeof(bufaddr));
- port_to_str(&qc->local_addr, bufport, sizeof(bufport));
- chunk_appendf(&trash, " local_addr=%s:%s", bufaddr, bufport);
+ if (ctx->fields & QUIC_DUMP_FLD_SOCK) {
+ chunk_appendf(&trash, " fd=%d", qc->fd);
+ if (qc->local_addr.ss_family == AF_INET ||
+ qc->local_addr.ss_family == AF_INET6) {
+ addr_to_str(&qc->local_addr, bufaddr, sizeof(bufaddr));
+ port_to_str(&qc->local_addr, bufport, sizeof(bufport));
+ chunk_appendf(&trash, " local_addr=%s:%s", bufaddr, bufport);
+
+ addr_to_str(&qc->peer_addr, bufaddr, sizeof(bufaddr));
+ port_to_str(&qc->peer_addr, bufport, sizeof(bufport));
+ chunk_appendf(&trash, " foreign_addr=%s:%s", bufaddr, bufport);
+ }
- addr_to_str(&qc->peer_addr, bufaddr, sizeof(bufaddr));
- port_to_str(&qc->peer_addr, bufport, sizeof(bufport));
- chunk_appendf(&trash, " foreign_addr=%s:%s", bufaddr, bufport);
+ chunk_appendf(&trash, "\n");
}
- chunk_appendf(&trash, "\n");
-
/* Packet number spaces information */
- pktns = qc->ipktns;
- if (pktns) {
- chunk_appendf(&trash, " [initl] rx.ackrng=%-6zu tx.inflight=%-6zu",
- pktns->rx.arngs.sz, pktns->tx.in_flight);
- }
+ if (ctx->fields & QUIC_DUMP_FLD_PKTNS) {
+ pktns = qc->ipktns;
+ if (pktns) {
+ chunk_appendf(&trash, " [initl] rx.ackrng=%-6zu tx.inflight=%-6zu\n",
+ pktns->rx.arngs.sz, pktns->tx.in_flight);
+ }
- pktns = qc->hpktns;
- if (pktns) {
- chunk_appendf(&trash, " [hndshk] rx.ackrng=%-6zu tx.inflight=%-6zu\n",
- pktns->rx.arngs.sz, pktns->tx.in_flight);
- }
+ pktns = qc->hpktns;
+ if (pktns) {
+ chunk_appendf(&trash, " [hndshk] rx.ackrng=%-6zu tx.inflight=%-6zu\n",
+ pktns->rx.arngs.sz, pktns->tx.in_flight);
+ }
- pktns = qc->apktns;
- if (pktns) {
- chunk_appendf(&trash, " [01rtt] rx.ackrng=%-6zu tx.inflight=%-6zu\n",
- pktns->rx.arngs.sz, pktns->tx.in_flight);
+ pktns = qc->apktns;
+ if (pktns) {
+ chunk_appendf(&trash, " [01rtt] rx.ackrng=%-6zu tx.inflight=%-6zu\n",
+ pktns->rx.arngs.sz, pktns->tx.in_flight);
+ }
}
- chunk_appendf(&trash, " srtt=%-4u rttvar=%-4u rttmin=%-4u ptoc=%-4u cwnd=%-6llu"
- " mcwnd=%-6llu sentpkts=%-6llu lostpkts=%-6llu reorderedpkts=%-6llu\n",
- qc->path->loss.srtt, qc->path->loss.rtt_var,
- qc->path->loss.rtt_min, qc->path->loss.pto_count, (ullong)qc->path->cwnd,
- (ullong)qc->path->mcwnd, (ullong)qc->cntrs.sent_pkt, (ullong)qc->path->loss.nb_lost_pkt, (ullong)qc->path->loss.nb_reordered_pkt);
+ if (ctx->fields & QUIC_DUMP_FLD_CC) {
+ chunk_appendf(&trash, " srtt=%-4u rttvar=%-4u rttmin=%-4u ptoc=%-4u cwnd=%-6llu"
+ " mcwnd=%-6llu sentpkts=%-6llu lostpkts=%-6llu reorderedpkts=%-6llu\n",
+ qc->path->loss.srtt, qc->path->loss.rtt_var,
+ qc->path->loss.rtt_min, qc->path->loss.pto_count, (ullong)qc->path->cwnd,
+ (ullong)qc->path->mcwnd, (ullong)qc->cntrs.sent_pkt, (ullong)qc->path->loss.nb_lost_pkt, (ullong)qc->path->loss.nb_reordered_pkt);
+ }
if (qc->cntrs.dropped_pkt) {
chunk_appendf(&trash, " droppkts=%-6llu", qc->cntrs.dropped_pkt);
@@ -256,23 +354,8 @@ static void dump_quic_full(struct show_quic_ctx *ctx, struct quic_conn *qc)
if (addnl)
chunk_appendf(&trash, "\n");
- /* Streams */
- node = eb64_first(&qc->streams_by_id);
- i = 0;
- while (node) {
- stream = eb64_entry(node, struct qc_stream_desc, by_id);
- node = eb64_next(node);
-
- chunk_appendf(&trash, " | stream=%-8llu", (unsigned long long)stream->by_id.key);
- chunk_appendf(&trash, " off=%-8llu ack=%-8llu",
- (unsigned long long)stream->buf_offset,
- (unsigned long long)stream->ack_offset);
-
- if (!(++i % 3)) {
- chunk_appendf(&trash, "\n");
- i = 0;
- }
- }
+ if (ctx->fields & QUIC_DUMP_FLD_MUX && qc->mux_state == QC_MUX_READY)
+ qcc_show_quic(qc->qcc);
chunk_appendf(&trash, "\n");
}
@@ -280,7 +363,6 @@ static void dump_quic_full(struct show_quic_ctx *ctx, struct quic_conn *qc)
static int cli_io_handler_dump_quic(struct appctx *appctx)
{
struct show_quic_ctx *ctx = appctx->svcctx;
- struct stconn *sc = appctx_sc(appctx);
struct quic_conn *qc;
thread_isolate();
@@ -288,16 +370,6 @@ static int cli_io_handler_dump_quic(struct appctx *appctx)
if (ctx->thr >= global.nbthread)
goto done;
- /* FIXME: Don't watch the other side !*/
- if (unlikely(sc_opposite(sc)->flags & SC_FL_SHUT_DONE)) {
- /* If we're forced to shut down, we might have to remove our
- * reference to the last stream being dumped.
- */
- if (!LIST_ISEMPTY(&ctx->bref.users))
- LIST_DEL_INIT(&ctx->bref.users);
- goto done;
- }
-
chunk_reset(&trash);
if (!LIST_ISEMPTY(&ctx->bref.users)) {
@@ -309,7 +381,7 @@ static int cli_io_handler_dump_quic(struct appctx *appctx)
ctx->bref.ref = ha_thread_ctx[ctx->thr].quic_conns.n;
/* Print legend for oneline format. */
- if (ctx->format == QUIC_DUMP_FMT_ONELINE) {
+ if (cli_show_quic_format(ctx) == QUIC_DUMP_FMT_ONELINE) {
chunk_appendf(&trash, "# conn/frontend state "
"in_flight infl_p lost_p "
"Local Address Foreign Address "
@@ -322,11 +394,12 @@ static int cli_io_handler_dump_quic(struct appctx *appctx)
int done = 0;
if (ctx->bref.ref == &ha_thread_ctx[ctx->thr].quic_conns) {
- /* If closing connections requested through "all", move
- * to quic_conns_clo list after browsing quic_conns.
- * Else move directly to the next quic_conns thread.
+ /* If closing connections requested through "all" or a
+ * specific connection is filtered, move to
+ * quic_conns_clo list after browsing quic_conns. Else
+ * move directly to the next quic_conns thread.
*/
- if (ctx->flags & QC_CLI_FL_SHOW_ALL) {
+ if (ctx->flags & QC_CLI_FL_SHOW_ALL || ctx->ptr) {
ctx->bref.ref = ha_thread_ctx[ctx->thr].quic_conns_clo.n;
continue;
}
@@ -344,6 +417,10 @@ static int cli_io_handler_dump_quic(struct appctx *appctx)
qc = LIST_ELEM(ctx->bref.ref, struct quic_conn *, el_th_ctx);
if ((int)(qc->qc_epoch - ctx->epoch) > 0)
done = 1;
+
+ /* Skip to next element if filter on a different connection. */
+ if (ctx->ptr && ctx->ptr != qc)
+ done = 1;
}
if (done) {
@@ -355,13 +432,17 @@ static int cli_io_handler_dump_quic(struct appctx *appctx)
continue;
}
- switch (ctx->format) {
- case QUIC_DUMP_FMT_FULL:
+ switch (cli_show_quic_format(ctx)) {
+ case QUIC_DUMP_FMT_CUST:
dump_quic_full(ctx, qc);
break;
case QUIC_DUMP_FMT_ONELINE:
dump_quic_oneline(ctx, qc);
break;
+
+ case QUIC_DUMP_FMT_DEFAULT:
+ /* An explicit format must be returned by cli_show_quic_format(). */
+ ABORT_NOW();
}
if (applet_putchk(appctx, &trash) == -1) {
@@ -371,6 +452,10 @@ static int cli_io_handler_dump_quic(struct appctx *appctx)
}
ctx->bref.ref = qc->el_th_ctx.n;
+
+ /* If filtered connection displayed, show quic can be stopped early. */
+ if (ctx->ptr)
+ goto done;
}
done:
@@ -395,7 +480,7 @@ static void cli_release_show_quic(struct appctx *appctx)
}
static struct cli_kw_list cli_kws = {{ }, {
- { { "show", "quic", NULL }, "show quic [oneline|full] [all] : display quic connections status", cli_parse_show_quic, cli_io_handler_dump_quic, cli_release_show_quic },
+ { { "show", "quic", NULL }, "show quic [<format>] [<filter>] : display quic connections status", cli_parse_show_quic, cli_io_handler_dump_quic, cli_release_show_quic },
{{},}
}};