]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: quic: Missing TX buffer draining from qc_send_ppkts()
authorFrédéric Lécaille <flecaille@haproxy.com>
Mon, 20 Feb 2023 08:28:58 +0000 (09:28 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 21 Feb 2023 10:06:10 +0000 (11:06 +0100)
If the TX buffer (->tx.buf) attached to the connection is not drained, there
are chances that this will be detected by qc_txb_release() which triggers
a BUG_ON_HOT() when this is the case as follows

[00|quic|2|c_conn.c:3477] UDP port unreachable : qc@0x5584f18d6d50 pto_count=0 cwnd=6816 ppif=1046 pif=1046
[00|quic|5|ic_conn.c:749] qc_kill_conn(): entering : qc@0x5584f18d6d50
[00|quic|5|ic_conn.c:752] qc_kill_conn(): leaving : qc@0x5584f18d6d50
[00|quic|5|c_conn.c:3532] qc_send_ppkts(): leaving : qc@0x5584f18d6d50 pto_count=0 cwnd=6816 ppif=1046 pif=1046

FATAL: bug condition "buf && b_data(buf)" matched at src/quic_conn.c:3098

Consume the remaining data in the TX buffer calling b_del().

This bug arrived with this commit:
    a2c62c314 MINOR: quic: Kill the connections on ICMP (port unreachable) packet receipt

Takes also the opportunity of this patch to modify the comments for qc_send_ppkts()
which should have arrived with a2c62c314 commit.

Must be backported to 2.7 where this latter commit is supposed to be backported.

src/quic_conn.c

index f40ae25e64947e45cfe9927e365a70deded98487..3de0d90054dfde2c0437cec77f1c6a9317510d7e 100644 (file)
@@ -3112,6 +3112,8 @@ static void qc_txb_release(struct quic_conn *qc)
        /* For the moment sending function is responsible to purge the buffer
         * entirely. It may change in the future but this requires to be able
         * to reuse old data.
+        * For the momemt we do not care to leave data in the buffer for
+        * a connection which is supposed to be killed asap.
         */
        BUG_ON_HOT(buf && b_data(buf));
 
@@ -3444,9 +3446,11 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
 
 /* Send datagrams stored in <buf>.
  *
- * This function always returns 1 for success. Even if sendto() syscall failed,
- * buffer is drained and packets are considered as emitted. QUIC loss detection
- * mechanism is used as a back door way to retry sending.
+ * This function returns 1 for success. Even if sendto() syscall failed,
+ * buffer is drained and packets are considered as emitted and this function returns 1
+ * There is a unique exception when sendto() fails with ECONNREFUSED as errno,
+ * this function returns 0.
+ * QUIC loss detection mechanism is used as a back door way to retry sending.
  */
 int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx)
 {
@@ -3494,6 +3498,7 @@ int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx)
                                        /* Let's kill this connection asap. */
                                        TRACE_PROTO("UDP port unreachable", QUIC_EV_CONN_SPPKTS, qc);
                                        qc_kill_conn(qc);
+                                       b_del(buf, buf->data);
                                        goto leave;
                                }