]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: quic: requeue datagrams received on wrong socket
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 5 Oct 2022 15:56:08 +0000 (17:56 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 2 Dec 2022 13:45:43 +0000 (14:45 +0100)
There is a small race condition when QUIC connection socket is
instantiated between the bind() and connect() system calls. This means
that the first datagram read on the sockets may belong to another
connection.

To detect this rare case, we compare the DCID for each QUIC datagram
read on the QUIC socket. If it does not match the connection CID, the
datagram is requeue using quic_receiver_buf to be able to handle it on
the correct thread.

This change is part of quic-conn owned socket implementation.
It may be backported to 2.7 after a period of observation.

src/quic_sock.c

index 5b10d8a8ad86f0ad72be0193814a0f35f25fbabd..284c9614d4b67dfb31b003e498fac0e22d183f44 100644 (file)
@@ -628,8 +628,37 @@ int qc_rcv_buf(struct quic_conn *qc)
                         *
                         * TODO count redispatch datagrams.
                         */
-                       TRACE_STATE("wrong datagram on quic-conn socket, prepare to requeue it", QUIC_EV_CONN_RCV, qc);
-                       ABORT_NOW();
+                       struct quic_receiver_buf *rxbuf;
+                       struct quic_dgram *tmp_dgram;
+                       unsigned char *rxbuf_tail;
+
+                       TRACE_STATE("datagram for other connection on quic-conn socket, requeue it", QUIC_EV_CONN_RCV, qc);
+
+                       rxbuf = MT_LIST_POP(&l->rx.rxbuf_list, typeof(rxbuf), rxbuf_el);
+
+                       tmp_dgram = quic_rxbuf_purge_dgrams(rxbuf);
+                       pool_free(pool_head_quic_dgram, tmp_dgram);
+
+                       if (b_contig_space(&rxbuf->buf) < new_dgram->len) {
+                               /* TODO count lost datagrams */
+                               MT_LIST_APPEND(&l->rx.rxbuf_list, &rxbuf->rxbuf_el);
+                               continue;
+                       }
+
+                       rxbuf_tail = (unsigned char *)b_tail(&rxbuf->buf);
+                       __b_putblk(&rxbuf->buf, (char *)dgram_buf, new_dgram->len);
+                       if (!quic_lstnr_dgram_dispatch(rxbuf_tail, ret, l, &qc->peer_addr, &daddr,
+                                                      new_dgram, &rxbuf->dgram_list)) {
+                               /* TODO count lost datagrams. */
+                               b_sub(&buf, ret);
+                       }
+                       else {
+                               /* datagram must not be freed as it was requeued. */
+                               new_dgram = NULL;
+                       }
+
+                       MT_LIST_APPEND(&l->rx.rxbuf_list, &rxbuf->rxbuf_el);
+                       continue;
                }
 
                quic_dgram_parse(new_dgram, qc, qc->li);