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,
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 */
#include <haproxy/quic_cc-t.h>
#include <haproxy/quic_frame-t.h>
#include <haproxy/quic_loss-t.h>
+#include <haproxy/quic_stats-t.h>
#include <haproxy/quic_tls-t.h>
#include <haproxy/quic_tp-t.h>
#include <haproxy/task.h>
#include <import/eb64tree.h>
#include <haproxy/quic_loss.h>
+#include <haproxy/xprt_quic-t.h>
+#include <haproxy/atomic.h>
#include <haproxy/ticks.h>
#include <haproxy/trace.h>
(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))
#include <haproxy/stats.h>
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",
.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" },
.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;
{
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);
/* Set <alert> 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);
}
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);
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)) {
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 <conn_opening> counter was not decremented. Note that if
+ * the <half_open_conn> 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
/* 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 };
*/
/* If the connection did not reached the handshake complete state,
- * the <conn_opening> counter was not decremented. Note that if
+ * the <half_open_conn> 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;
}
* from <fd> UDP socket to <dst>
* 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
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;
}
}
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);
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);
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;
}