]> git.kaiwu.me - haproxy.git/commitdiff
OPTIM: quic: reduce the size of struct quic_dgram
authorMaxime Henrion <mhenrion@haproxy.com>
Tue, 21 Apr 2026 19:25:58 +0000 (15:25 -0400)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 30 Apr 2026 13:33:07 +0000 (15:33 +0200)
The QUIC code can only handle IPv4 or IPv6 addresses, so using two
sockaddr_storage structs wastes a lot of space in the quic_dgram struct.
This is a very large overhead since this structure is written in the MPSC
ring buffers before every datagram, while many of those datagrams are only
50 bytes or less. Using an union instead saves 200 bytes per datagram,
increasing the capacity of the buffers significantly.

include/haproxy/quic_rx-t.h
include/haproxy/quic_sock-t.h
src/quic_retry.c
src/quic_rules.c
src/quic_rx.c
src/quic_sock.c
src/quic_token.c
src/quic_trace.c

index 686e6fff131dc308f0a400d8ee471cdb15272bd4..9bfe6fbb1af8cf43555ca98665c12c366d30841f 100644 (file)
@@ -7,6 +7,7 @@ extern struct pool_head *pool_head_quic_rx_packet;
 #include <import/eb64tree.h>
 #include <haproxy/api-t.h>
 #include <haproxy/quic_cid-t.h>
+#include <haproxy/quic_sock-t.h>
 #include <inttypes.h>
 #include <sys/socket.h>
 
@@ -52,7 +53,7 @@ struct quic_rx_packet {
        struct eb64_node pn_node;
        volatile unsigned int refcnt;
        /* Source address of this packet. */
-       struct sockaddr_storage saddr;
+       union sockaddr_in46 saddr;
        unsigned int flags;
        unsigned int time_received;
 };
index 7358017572b09c073ba95fb4d0833153a3ab1de4..19bf8d51e8d94ccec6d72f662ca42505f4f52d1c 100644 (file)
@@ -21,6 +21,11 @@ struct quic_accept_queue {
 #define QUIC_DGRAM_FL_REJECT                   0x00000001
 #define QUIC_DGRAM_FL_SEND_RETRY               0x00000002
 
+union sockaddr_in46 {
+       struct sockaddr_in in4;
+       struct sockaddr_in6 in6;
+};
+
 /* QUIC datagram */
 struct quic_dgram {
        enum obj_type obj_type;
@@ -29,8 +34,8 @@ struct quic_dgram {
        size_t len;
        size_t dcid_off;
        size_t dcid_len;
-       struct sockaddr_storage saddr;
-       struct sockaddr_storage daddr;
+       union sockaddr_in46 saddr;
+       union sockaddr_in46 daddr;
        struct quic_conn *qc;
 
        int flags; /* QUIC_DGRAM_FL_* values */
index 2ac981034e23a3f24455e18cbc6e09edf9879ff8..23b74d8fca51ef4894581d95c9c33d58312ff812 100644 (file)
@@ -283,7 +283,8 @@ int quic_retry_token_check(struct quic_rx_packet *pkt,
                goto err;
        }
 
-       aadlen = quic_generate_retry_token_aad(aad, qv->num, &pkt->scid, &dgram->saddr);
+       aadlen = quic_generate_retry_token_aad(aad, qv->num, &pkt->scid,
+                                              (struct sockaddr_storage *)&dgram->saddr);
        salt = token + tokenlen - QUIC_RETRY_TOKEN_SALTLEN;
        if (!quic_tls_derive_retry_token_secret(EVP_sha256(), key, sizeof key, iv, sizeof iv,
                                                salt, QUIC_RETRY_TOKEN_SALTLEN, sec, seclen)) {
index d73a4a7e420a0bcba6e0c768c015e7d040e79f19..55ccb899cee67d65cb1a75cdb3ee1482410c8937 100644 (file)
@@ -28,8 +28,8 @@ int quic_init_exec_rules(struct listener *li, struct quic_dgram *dgram)
         */
        rule_sess.fe = px;
        rule_sess.listener = li;
-       rule_sess.src = &dgram->saddr;
-       rule_sess.dst = &dgram->daddr;
+       rule_sess.src = (struct sockaddr_storage *)&dgram->saddr;
+       rule_sess.dst = (struct sockaddr_storage *)&dgram->daddr;
        rule_sess.origin = &dgram->obj_type;
 
        list_for_each_entry(rule, &px->quic_init_rules, list) {
index 4f2cb14a9324b5a3053642210d5580becba2b59e..6c1c2733bcd21946a8b6841aa553ad7e322cf459 100644 (file)
@@ -1753,7 +1753,7 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
        prx = l->bind_conf->frontend;
        prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module);
 
-       qc = retrieve_qc_conn_from_cid(pkt, &dgram->saddr, new_tid);
+       qc = retrieve_qc_conn_from_cid(pkt, (struct sockaddr_storage *)&dgram->saddr, new_tid);
 
        /* quic_conn must be set to NULL if bind on another thread. */
        BUG_ON_HOT(qc && *new_tid != -1);
@@ -1788,7 +1788,7 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                                /* Validate the token, retry or not only when connection is unknown. */
                                if (!quic_token_validate(pkt, dgram, l, qc, &token_odcid)) {
                                        if (dgram->flags & QUIC_DGRAM_FL_SEND_RETRY) {
-                                               if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) {
+                                               if (send_retry(l->rx.fd, (struct sockaddr_storage *)&dgram->saddr, pkt, pkt->version)) {
                                                        TRACE_ERROR("Error during Retry generation",
                                                                    QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
                                                }
@@ -1818,7 +1818,7 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
 
                                        TRACE_PROTO("Initial without token, sending retry",
                                                    QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
-                                       if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) {
+                                       if (send_retry(l->rx.fd, (struct sockaddr_storage *)&dgram->saddr, pkt, pkt->version)) {
                                                TRACE_ERROR("Error during Retry generation",
                                                            QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
                                                goto out;
@@ -1850,7 +1850,7 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                                goto err;
                        }
 
-                       if (quic_cid_derive_from_odcid(conn_id, &pkt->dcid, &pkt->saddr)) {
+                       if (quic_cid_derive_from_odcid(conn_id, &pkt->dcid, (struct sockaddr_storage *)&pkt->saddr)) {
                                TRACE_ERROR("error on CID generation",
                                            QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
                                pool_free(pool_head_quic_connection_id, conn_id);
@@ -1868,8 +1868,9 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                                pool_free(pool_head_quic_connection_id, conn_id);
                        }
                        else {
-                               qc = qc_new_conn(l, pkt, &token_odcid,
-                                                NULL, conn_id, &dgram->daddr, &pkt->saddr);
+                               qc = qc_new_conn(l, pkt, &token_odcid, NULL, conn_id,
+                                                (struct sockaddr_storage *)&dgram->daddr,
+                                                (struct sockaddr_storage *)&pkt->saddr);
                                if (qc == NULL) {
                                        quic_cid_delete(conn_id); /* Removes CID from global tree as it points to a NULL qc. */
                                        pool_free(pool_head_quic_connection_id, conn_id);
@@ -1896,7 +1897,7 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                 * emits stateless_reset_token in its TPs.
                 */
                TRACE_PROTO("RX non Initial pkt without connection", QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
-               if (!send_stateless_reset(l, &dgram->saddr, pkt))
+               if (!send_stateless_reset(l, (struct sockaddr_storage *)&dgram->saddr, pkt))
                        TRACE_ERROR("stateless reset not sent", QUIC_EV_CONN_LPKT, qc);
                goto err;
        }
@@ -1993,7 +1994,7 @@ static int quic_rx_pkt_parse(struct quic_conn *qc, struct quic_rx_packet *pkt,
                 */
                if (l && !pkt->version) {
                         /* unsupported version, send Negotiation packet */
-                       if (send_version_negotiation(l->rx.fd, &dgram->saddr, pkt)) {
+                       if (send_version_negotiation(l->rx.fd, (struct sockaddr_storage *)&dgram->saddr, pkt)) {
                                TRACE_ERROR("VN packet not sent", QUIC_EV_CONN_LPKT);
                                goto drop_silent;
                        }
@@ -2489,8 +2490,10 @@ int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc,
                }
 
                /* Detect QUIC connection migration. */
-               if (li && ipcmp(&qc->peer_addr, &dgram->saddr, 1)) {
-                       if (qc_handle_conn_migration(qc, &dgram->saddr, &dgram->daddr)) {
+               if (li && ipcmp(&qc->peer_addr, (struct sockaddr_storage *)&dgram->saddr, 1)) {
+                       if (qc_handle_conn_migration(qc,
+                           (struct sockaddr_storage *)&dgram->saddr,
+                           (struct sockaddr_storage *)&dgram->daddr)) {
                                /* Skip the entire datagram. */
                                TRACE_ERROR("error during connection migration, datagram dropped", QUIC_EV_CONN_LPKT, qc);
                                pkt->len = end - pos;
index ea9a8e0e3031e10c98f60cc6927ed60bd02fa3f1..4620e612fc3dc14234a85cf6450da6f384061aeb 100644 (file)
@@ -267,14 +267,16 @@ static void quic_dgram_init(struct quic_dgram *dgram,
                             struct sockaddr_storage *saddr,
                             struct sockaddr_storage *daddr)
 {
+       BUG_ON_HOT(!is_inet_addr(saddr) || !is_inet_addr(daddr));
+
        dgram->obj_type = OBJ_TYPE_DGRAM;
        dgram->owner = owner;
        dgram->buf = pos;
        dgram->len = len;
        dgram->dcid_off = dcid_off;
        dgram->dcid_len = dcid_len;
-       dgram->saddr = *saddr;
-       dgram->daddr = *daddr;
+       memcpy(&dgram->saddr, saddr, sizeof(dgram->saddr));
+       memcpy(&dgram->daddr, daddr, sizeof(dgram->daddr));
        dgram->qc = NULL;
        dgram->flags = 0;
 }
@@ -432,7 +434,8 @@ int quic_dgram_requeue(struct quic_dgram *dgram, int cid_tid)
 {
        return quic_dgram_write(dgram->buf, dgram->len, dgram->owner,
                                dgram->dcid_off, dgram->dcid_len,
-                               &dgram->saddr, &dgram->daddr, cid_tid);
+                               (struct sockaddr_storage *)&dgram->saddr,
+                               (struct sockaddr_storage *)&dgram->daddr, cid_tid);
 }
 
 /* Attempt to push a datagram to its handler thread.
index 9c1d69cd1fd33fe882182548219911d5dd30cd6b..5200225ef08a04a1808d816cd00f5ad3a294f2ef 100644 (file)
@@ -135,7 +135,7 @@ int quic_token_check(struct quic_rx_packet *pkt,
        }
 
        /* Generate the AAD. */
-       aadlen = ipaddrcpy(aad, &dgram->saddr);
+       aadlen = ipaddrcpy(aad, (struct sockaddr_storage *)&dgram->saddr);
        rand = token + tokenlen - QUIC_TOKEN_RAND_DLEN;
        if (!quic_tls_derive_token_secret(EVP_sha256(), key, sizeof key, iv, sizeof iv,
                                          rand, QUIC_TOKEN_RAND_DLEN, sec, seclen)) {
index 2dd12b805e4032766bcb7d41fd8282d0a42498d7..21d8bc72c9bcdf85af3414b2f3a5e695b6e455ae 100644 (file)
@@ -606,6 +606,7 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace
        if (mask & QUIC_EV_CONN_RCV) {
                int i;
                const struct quic_dgram *dgram = a2;
+               const struct sockaddr_storage *saddr, *daddr;
                char bufaddr[INET6_ADDRSTRLEN], bufport[6];
 
                if (qc) {
@@ -617,14 +618,15 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace
                if (dgram) {
                        chunk_appendf(&trace_buf, " dgram.len=%zu", dgram->len);
                        /* Socket */
-                       if (dgram->saddr.ss_family == AF_INET ||
-                               dgram->saddr.ss_family == AF_INET6) {
-                               addr_to_str(&dgram->saddr, bufaddr, sizeof(bufaddr));
-                               port_to_str(&dgram->saddr, bufport, sizeof(bufport));
+                       saddr = (struct sockaddr_storage *)&dgram->saddr;
+                       daddr = (struct sockaddr_storage *)&dgram->daddr;
+                       if (saddr->ss_family == AF_INET || saddr->ss_family == AF_INET6) {
+                               addr_to_str(saddr, bufaddr, sizeof(bufaddr));
+                               port_to_str(saddr, bufport, sizeof(bufport));
                                chunk_appendf(&trace_buf, "saddr=%s:%s ", bufaddr, bufport);
 
-                               addr_to_str(&dgram->daddr, bufaddr, sizeof(bufaddr));
-                               port_to_str(&dgram->daddr, bufport, sizeof(bufport));
+                               addr_to_str(daddr, bufaddr, sizeof(bufaddr));
+                               port_to_str(daddr, bufport, sizeof(bufport));
                                chunk_appendf(&trace_buf, "daddr=%s:%s ", bufaddr, bufport);
                        }
                        /* DCID */