diff --git a/include/haproxy/quic_stats-t.h b/include/haproxy/quic_stats-t.h index 7a8b8085e..6f5fca850 100644 --- a/include/haproxy/quic_stats-t.h +++ b/include/haproxy/quic_stats-t.h @@ -9,13 +9,16 @@ extern struct stats_module quic_stats_module; enum { - QUIC_ST_DROPPED_PACKETS, + QUIC_ST_DROPPED_PACKET, + QUIC_ST_DROPPED_PARSING, + QUIC_ST_LOST_PACKET, QUIC_ST_TOO_SHORT_INITIAL_DGRAM, QUIC_ST_RETRY_SENT, QUIC_ST_RETRY_VALIDATED, QUIC_ST_RETRY_ERRORS, - QUIC_ST_CONN_OPENINGS, - QUIC_ST_HDSHK_FAILS, + QUIC_ST_HALF_OPEN_CONN, + QUIC_ST_HDSHK_FAIL, + QUIC_ST_STATELESS_RESET_SENT, /* Transport errors */ QUIC_ST_TRANSP_ERR_NO_ERROR, QUIC_ST_TRANSP_ERR_INTERNAL_ERROR, @@ -46,12 +49,15 @@ enum { struct quic_counters { long long dropped_pkt; /* total number of dropped packets */ + long long dropped_parsing; /* total number of dropped packets upon parsing errors */ + long long lost_pkt; /* total number of lost packets */ long long too_short_initial_dgram; /* total number of too short datagrams with Initial packets */ long long retry_sent; /* total number of Retry sent */ long long retry_validated; /* total number of validated Retry tokens */ long long retry_error; /* total number of Retry token errors */ - long long conn_opening; /* total number of connection openings */ + long long half_open_conn; /* total number of half open connections */ long long hdshk_fail; /* total number of handshake failures */ + long long stateless_reset_sent; /* total number of handshake failures */ /* Transport errors */ long long quic_transp_err_no_error; /* total number of NO_ERROR connection errors */ long long quic_transp_err_internal_error; /* total number of INTERNAL_ERROR connection errors */ diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h index 36b85e8b2..b8bdef74a 100644 --- a/include/haproxy/xprt_quic-t.h +++ b/include/haproxy/xprt_quic-t.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/src/quic_loss.c b/src/quic_loss.c index 42eb5a251..72f5a28ea 100644 --- a/src/quic_loss.c +++ b/src/quic_loss.c @@ -1,7 +1,9 @@ #include #include +#include +#include #include #include @@ -175,6 +177,7 @@ void qc_packet_loss_lookup(struct quic_pktns *pktns, struct quic_conn *qc, (int64_t)largest_acked_pn >= pkt->pn_node.key + QUIC_LOSS_PACKET_THRESHOLD) { eb64_delete(&pkt->pn_node); LIST_APPEND(lost_pkts, &pkt->list); + HA_ATOMIC_INC(&qc->prx_counters->lost_pkt); } else { if (tick_isset(pktns->tx.loss_time)) diff --git a/src/quic_stats.c b/src/quic_stats.c index cc81924b9..16977109a 100644 --- a/src/quic_stats.c +++ b/src/quic_stats.c @@ -2,8 +2,12 @@ #include static struct name_desc quic_stats[] = { - [QUIC_ST_DROPPED_PACKETS] = { .name = "quic_dropped_pkt", + [QUIC_ST_DROPPED_PACKET] = { .name = "quic_dropped_pkt", .desc = "Total number of dropped packets" }, + [QUIC_ST_DROPPED_PARSING] = { .name = "quic_dropped_parsing_pkt", + .desc = "Total number of dropped packets upon parsing error" }, + [QUIC_ST_LOST_PACKET] = { .name = "quic_lost_pkt", + .desc = "Total number of lost sent packets" }, [QUIC_ST_TOO_SHORT_INITIAL_DGRAM] = { .name = "quic_too_short_dgram", .desc = "Total number of too short dgrams with Initial packets" }, [QUIC_ST_RETRY_SENT] = { .name = "quic_retry_sent", @@ -12,10 +16,12 @@ static struct name_desc quic_stats[] = { .desc = "Total number of validated Retry tokens" }, [QUIC_ST_RETRY_ERRORS] = { .name = "quic_retry_error", .desc = "Total number of Retry tokens errors" }, - [QUIC_ST_CONN_OPENINGS] = { .name = "quic_conn_opening", - .desc = "Total number of connection openings" }, - [QUIC_ST_HDSHK_FAILS] = { .name = "quic_hdshk_fail", + [QUIC_ST_HALF_OPEN_CONN] = { .name = "quic_half_open_conn", + .desc = "Total number of half open connections" }, + [QUIC_ST_HDSHK_FAIL] = { .name = "quic_hdshk_fail", .desc = "Total number of handshake failures" }, + [QUIC_ST_STATELESS_RESET_SENT] = { .name = "quic_stless_rst_sent", + .desc = "Total number of stateless reset packet sent" }, /* Transport errors */ [QUIC_ST_TRANSP_ERR_NO_ERROR] = { .name = "quic_transp_err_no_error", .desc = "Total number of NO_ERROR errors received" }, @@ -57,13 +63,13 @@ static struct name_desc quic_stats[] = { .desc = "Total number of UNKNOWN_ERROR errors received" }, /* Streams related counters */ [QUIC_ST_DATA_BLOCKED] = { .name = "quic_data_blocked", - .desc = "Total number of times DATA_BLOCKED frame was received" }, + .desc = "Total number of received DATA_BLOCKED frames" }, [QUIC_ST_STREAM_DATA_BLOCKED] = { .name = "quic_stream_data_blocked", - .desc = "Total number of times STREAMS_BLOCKED frame was received" }, + .desc = "Total number of received STREAMS_BLOCKED frames" }, [QUIC_ST_STREAMS_DATA_BLOCKED_BIDI] = { .name = "quic_streams_data_blocked_bidi", - .desc = "Total number of times STREAM_DATA_BLOCKED_BIDI frame was received" }, + .desc = "Total number of received STREAM_DATA_BLOCKED_BIDI frames" }, [QUIC_ST_STREAMS_DATA_BLOCKED_UNI] = { .name = "quic_streams_data_blocked_bidi", - .desc = "Total number of times STREAM_DATA_BLOCKED_UNI frame was received" }, + .desc = "Total number of received STREAM_DATA_BLOCKED_UNI frames" }, }; struct quic_counters quic_counters; @@ -72,13 +78,16 @@ static void quic_fill_stats(void *data, struct field *stats) { struct quic_counters *counters = data; - stats[QUIC_ST_DROPPED_PACKETS] = mkf_u64(FN_COUNTER, counters->dropped_pkt); + stats[QUIC_ST_DROPPED_PACKET] = mkf_u64(FN_COUNTER, counters->dropped_pkt); + stats[QUIC_ST_DROPPED_PARSING] = mkf_u64(FN_COUNTER, counters->dropped_parsing); + stats[QUIC_ST_LOST_PACKET] = mkf_u64(FN_COUNTER, counters->lost_pkt); stats[QUIC_ST_TOO_SHORT_INITIAL_DGRAM] = mkf_u64(FN_COUNTER, counters->too_short_initial_dgram); stats[QUIC_ST_RETRY_SENT] = mkf_u64(FN_COUNTER, counters->retry_sent); stats[QUIC_ST_RETRY_VALIDATED] = mkf_u64(FN_COUNTER, counters->retry_validated); stats[QUIC_ST_RETRY_ERRORS] = mkf_u64(FN_COUNTER, counters->retry_error); - stats[QUIC_ST_CONN_OPENINGS] = mkf_u64(FN_GAUGE, counters->conn_opening); - stats[QUIC_ST_HDSHK_FAILS] = mkf_u64(FN_COUNTER, counters->hdshk_fail); + stats[QUIC_ST_HALF_OPEN_CONN] = mkf_u64(FN_GAUGE, counters->half_open_conn); + stats[QUIC_ST_HDSHK_FAIL] = mkf_u64(FN_COUNTER, counters->hdshk_fail); + stats[QUIC_ST_STATELESS_RESET_SENT] = mkf_u64(FN_COUNTER, counters->stateless_reset_sent); /* Transport errors */ stats[QUIC_ST_TRANSP_ERR_NO_ERROR] = mkf_u64(FN_COUNTER, counters->quic_transp_err_no_error); stats[QUIC_ST_TRANSP_ERR_INTERNAL_ERROR] = mkf_u64(FN_COUNTER, counters->quic_transp_err_internal_error); diff --git a/src/xprt_quic.c b/src/xprt_quic.c index dd1bbbe7e..cc4457142 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -1120,7 +1120,7 @@ void quic_set_connection_close(struct quic_conn *qc, int err, int app) /* Set TLS alert as QUIC CRYPTO_ERROR error */ void quic_set_tls_alert(struct quic_conn *qc, int alert) { - HA_ATOMIC_DEC(&qc->prx_counters->conn_opening); + HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); quic_set_connection_close(qc, QC_ERR_CRYPTO_ERROR | alert, 0); qc->flags |= QUIC_FL_CONN_TLS_ALERT; TRACE_PROTO("Alert set", QUIC_EV_CONN_SSLDATA, qc); @@ -2109,7 +2109,7 @@ static inline int qc_provide_cdata(struct quic_enc_level *el, } HA_ATOMIC_INC(&qc->prx_counters->hdshk_fail); - HA_ATOMIC_DEC(&qc->prx_counters->conn_opening); + HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); TRACE_DEVEL("SSL handshake error", QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err); qc_ssl_dump_errors(ctx->conn); @@ -2126,7 +2126,7 @@ static inline int qc_provide_cdata(struct quic_enc_level *el, goto err; } - HA_ATOMIC_DEC(&qc->prx_counters->conn_opening); + HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); /* I/O callback switch */ ctx->wait_event.tasklet->process = quic_conn_app_io_cb; if (qc_is_listener(ctx->qc)) { @@ -2564,12 +2564,12 @@ static int qc_parse_pkt_frms(struct quic_rx_packet *pkt, struct ssl_sock_ctx *ct qc_cc_err_count_inc(qc->prx_counters, frm.type, frm.connection_close.error_code); if (!(qc->flags & QUIC_FL_CONN_DRAINING)) { /* If the connection did not reached the handshake complete state, - * the counter was not decremented. Note that if + * the counter was not decremented. Note that if * a TLS alert was received from the TLS stack, this counter * has already been decremented. */ if (qc->state < QUIC_HS_ST_COMPLETE && !(qc->flags & QUIC_FL_CONN_TLS_ALERT)) - HA_ATOMIC_DEC(&qc->prx_counters->conn_opening); + HA_ATOMIC_DEC(&qc->prx_counters->half_open_conn); TRACE_PROTO("Entering draining state", QUIC_EV_CONN_PRSHPKT, qc); /* RFC 9000 10.2. Immediate Close: * The closing and draining connection states exist to ensure @@ -3559,6 +3559,7 @@ int qc_treat_rx_pkts(struct quic_enc_level *cur_el, struct quic_enc_level *next_ /* Drop the packet */ TRACE_PROTO("packet parsing failed -> dropped", QUIC_EV_CONN_ELRXPKTS, ctx->qc, pkt); + HA_ATOMIC_INC(&qc->prx_counters->dropped_parsing); } else { struct quic_arng ar = { .first = pkt->pn, .last = pkt->pn }; @@ -4466,12 +4467,12 @@ static struct task *qc_idle_timer_task(struct task *t, void *ctx, unsigned int s */ /* If the connection did not reached the handshake complete state, - * the counter was not decremented. Note that if + * the counter was not decremented. Note that if * a TLS alert was received from the TLS stack, this counter * has already been decremented. */ if (qc_state < QUIC_HS_ST_COMPLETE && !(qc_flags & QUIC_FL_CONN_TLS_ALERT)) - HA_ATOMIC_DEC(&prx_counters->conn_opening); + HA_ATOMIC_DEC(&prx_counters->half_open_conn); return NULL; } @@ -4721,13 +4722,17 @@ static int send_version_negotiation(int fd, struct sockaddr_storage *addr, * from UDP socket to * Return 1 if succeeded, 0 if not. */ -static int send_stateless_reset(int fd, struct sockaddr_storage *dstaddr, +static int send_stateless_reset(struct listener *l, struct sockaddr_storage *dstaddr, struct quic_rx_packet *rxpkt) { int pktlen, rndlen; unsigned char pkt[64]; const socklen_t addrlen = get_addr_len(dstaddr); + struct proxy *prx; + struct quic_counters *prx_counters; + prx = l->bind_conf->frontend; + prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module); /* 10.3 Stateless Reset (https://www.rfc-editor.org/rfc/rfc9000.html#section-10.3) * The resulting minimum size of 21 bytes does not guarantee that a Stateless * Reset is difficult to distinguish from other packets if the recipient requires @@ -4755,9 +4760,10 @@ static int send_stateless_reset(int fd, struct sockaddr_storage *dstaddr, rxpkt->dcid.data, rxpkt->dcid.len)) return 0; - if (sendto(fd, pkt, pktlen, 0, (struct sockaddr *)dstaddr, addrlen) < 0) + if (sendto(l->rx.fd, pkt, pktlen, 0, (struct sockaddr *)dstaddr, addrlen) < 0) return 0; + HA_ATOMIC_INC(&prx_counters->stateless_reset_sent); TRACE_PROTO("stateless reset sent", QUIC_EV_STATELESS_RST, NULL, &rxpkt->dcid); return 1; } @@ -5328,7 +5334,7 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, } if (global.cluster_secret && !pkt->token_len && !(l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) && - HA_ATOMIC_LOAD(&prx_counters->conn_opening) >= global.tune.quic_retry_threshold) { + HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) { TRACE_PROTO("Initial without token, sending retry", QUIC_EV_CONN_LPKT); if (send_retry(l->rx.fd, &dgram->saddr, pkt)) { TRACE_PROTO("Error during Retry generation", QUIC_EV_CONN_LPKT); @@ -5357,7 +5363,7 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, if (qc == NULL) goto drop; - HA_ATOMIC_INC(&prx_counters->conn_opening); + HA_ATOMIC_INC(&prx_counters->half_open_conn); /* Insert the DCID the QUIC client has chosen (only for listeners) */ n = ebmb_insert(&quic_dghdlrs[tid].odcids, &qc->odcid_node, qc->odcid.len + qc->odcid.addrlen); @@ -5414,7 +5420,7 @@ static void qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, if (!qc) { size_t pktlen = end - buf; TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, NULL, pkt, &pktlen); - if (global.cluster_secret && !send_stateless_reset(l->rx.fd, &dgram->saddr, pkt)) + if (global.cluster_secret && !send_stateless_reset(l, &dgram->saddr, pkt)) TRACE_PROTO("stateless reset not sent", QUIC_EV_CONN_LPKT, qc); goto drop; }