diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index 56367f1b4..37050f865 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index 1829b9763..bed933226 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -172,6 +172,7 @@ enum srv_init_state { #define SRV_F_DELETED 0x8000 /* srv is deleted but not yet purged */ #define SRV_F_STRICT_MAXCONN 0x10000 /* maxconn is to be strictly enforced, as a limit of outbound connections */ #define SRV_F_CHK_NO_AUTO_SNI 0x20000 /* disable automatic SNI selection for healthcheck */ +#define SRV_F_UDP_GSO_NOTSUPP 0x40000 /* UDP GSO is disabled due to a previous error encountered */ /* configured server options for send-proxy (server->pp_opts) */ #define SRV_PP_V1 0x0001 /* proxy protocol version 1 */ diff --git a/src/quic_conn.c b/src/quic_conn.c index 7c0fcb7da..d55be2b41 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -1197,6 +1197,10 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, struct quic_connection_id *conn_cid = NULL; qc->flags = QUIC_FL_CONN_IS_BACK|QUIC_FL_CONN_PEER_VALIDATED_ADDR; + /* Duplicate GSO status on server to connection */ + if (HA_ATOMIC_LOAD(&srv->flags) & SRV_F_UDP_GSO_NOTSUPP) + qc->flags |= QUIC_FL_CONN_UDP_GSO_EIO; + qc->state = QUIC_HS_ST_CLIENT_INITIAL; /* This is the original connection ID from the peer server diff --git a/src/quic_tx.c b/src/quic_tx.c index 10a6c5e65..6c5631651 100644 --- a/src/quic_tx.c +++ b/src/quic_tx.c @@ -289,10 +289,8 @@ static int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx) int ret = 0; struct quic_conn *qc; char skip_sendto = 0; - struct listener *l; qc = ctx->qc; - l = objt_listener(qc->target); TRACE_ENTER(QUIC_EV_CONN_SPPKTS, qc); while (b_contig_data(buf, 0)) { unsigned char *pos; @@ -333,15 +331,19 @@ static int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx) /* GSO must not be used if already disabled. */ BUG_ON(qc->flags & QUIC_FL_CONN_UDP_GSO_EIO); - /* TODO: note that at this time for connection to backends this - * part is not run because no more than an MTU has been - * prepared for such connections (l is not NULL). - */ - /* Disable permanently UDP GSO for this listener. - * Retry standard emission. - */ - TRACE_ERROR("mark listener UDP GSO as unsupported", QUIC_EV_CONN_SPPKTS, qc, first_pkt); - HA_ATOMIC_OR(&l->flags, LI_F_UDP_GSO_NOTSUPP); + /* Permanently disable UDP GSO for future conns which use current listener/server instance. */ + if (!qc_is_back(qc)) { + struct listener *l = __objt_listener(qc->target); + TRACE_ERROR("mark listener UDP GSO as unsupported", QUIC_EV_CONN_SPPKTS, qc, first_pkt); + HA_ATOMIC_OR(&l->flags, LI_F_UDP_GSO_NOTSUPP); + } + else if (qc->conn) { + struct server *srv = __objt_server(qc->conn->target); + TRACE_ERROR("mark server UDP GSO as unsupported", QUIC_EV_CONN_SPPKTS, qc, first_pkt); + HA_ATOMIC_OR(&srv->flags, SRV_F_UDP_GSO_NOTSUPP); + } + + /* Retry emission without GSO. */ qc->flags |= QUIC_FL_CONN_UDP_GSO_EIO; continue; } @@ -813,9 +815,6 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf, dglen == qc->path->mtu && (char *)end < b_wrap(buf) && ++gso_dgram_cnt < QUIC_MAX_GSO_DGRAMS) { - /* TODO: note that for backends GSO is not used. No more than - * an MTU is prepared. - */ /* A datagram covering the full MTU has been * built, use GSO to built next entry. Do not * reserve extra space for datagram header.