MINOR: quic: specify show quic output fields

Add the possibility to customize show quic full output with only a
specific set of printed fields. This is specified as a comma-separated
list. Here are the currently supported values :
* tp: transport parameters
* sock: connection addresses and socket FD
* pktns: packet number space with ack ranges and in flight bytes
* cc: congestion controler and loss information

Note that streams output is not filtered by this mechanism. It's because
it will be replaced soon by an output generated from the MUX which will
use its owned field name.
This commit is contained in:
Amaury Denoyelle 2024-02-26 09:57:05 +01:00
parent c4f5ff8369
commit dda3a0d8fc
2 changed files with 113 additions and 46 deletions

View File

@ -3067,14 +3067,17 @@ show resolvers [<resolvers section id>]
too_big: too big response
outdated: number of response arrived too late (after another name server)
show quic [oneline|full] [<filter>]
show quic [<format>] [<filter>]
Dump information on all active QUIC frontend connections. This command is
restricted and can only be issued on sockets configured for levels "operator"
or "admin".
An optional format can be specified as first argument to control the
verbosity. Currently supported values are "oneline" which is the default if
format is unspecified or "full".
An optional argument can be specified to control the verbosity. Its value can
be interpreted in different way. The first possibility is to used predefined
values, "oneline" for the default format and "full" to display all
information. Alternatively, a list of comma-delimited fields can be specified
to restrict output. Currently supported values are "tp", "sock", "pktns" and
"cc".
The final argument is used to restrict or extend the connection list. By
default, connections on closing or draining state are not displayed. Use the

View File

@ -14,9 +14,16 @@ enum quic_dump_format {
QUIC_DUMP_FMT_DEFAULT, /* value used if not explicitely 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
/* Do not forget to update FLD_MASK when adding a new field. */
#define QUIC_DUMP_FLD_MASK 0x000f
/* appctx context used by "show quic" command */
struct show_quic_ctx {
unsigned int epoch;
@ -25,6 +32,7 @@ struct show_quic_ctx {
int flags;
enum quic_dump_format format;
void *ptr;
int fields;
};
#define QC_CLI_FL_SHOW_ALL 0x1 /* show closing/draining connections */
@ -36,7 +44,7 @@ struct show_quic_ctx {
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_FULL : QUIC_DUMP_FMT_ONELINE;
return ctx->ptr ? QUIC_DUMP_FMT_CUST : QUIC_DUMP_FMT_ONELINE;
else
return ctx->format;
}
@ -54,15 +62,58 @@ static int cli_parse_show_quic(char **args, char *payload, struct appctx *appctx
ctx->flags = 0;
ctx->format = QUIC_DUMP_FMT_DEFAULT;
ctx->ptr = 0;
ctx->fields = 0;
if (strcmp(args[argc], "oneline") == 0) {
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 {
/* 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]);
@ -74,6 +125,11 @@ static int cli_parse_show_quic(char **args, char *payload, struct appctx *appctx
cli_err(appctx, "Invalid quic_conn pointer.\n");
return 1;
}
if (!ctx->fields)
ctx->fields = QUIC_DUMP_FLD_MASK;
++argc;
}
else if (istmatch(istarg, ist("all"))) {
ctx->flags |= QC_CLI_FL_SHOW_ALL;
@ -168,12 +224,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)
@ -201,45 +259,51 @@ 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->apktns;
if (pktns) {
chunk_appendf(&trash, " [01rtt] 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);
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);
}
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 (qc->cntrs.dropped_pkt) {
chunk_appendf(&trash, " droppkts=%-6llu", qc->cntrs.dropped_pkt);
addnl = 1;
@ -392,7 +456,7 @@ static int cli_io_handler_dump_quic(struct appctx *appctx)
}
switch (cli_show_quic_format(ctx)) {
case QUIC_DUMP_FMT_FULL:
case QUIC_DUMP_FMT_CUST:
dump_quic_full(ctx, qc);
break;
case QUIC_DUMP_FMT_ONELINE:
@ -439,7 +503,7 @@ static void cli_release_show_quic(struct appctx *appctx)
}
static struct cli_kw_list cli_kws = {{ }, {
{ { "show", "quic", NULL }, "show quic [oneline|full] [<filter>] : 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 },
{{},}
}};